создайте объект из dict с помощью cattr/attr со значением по умолчанию None

#python #python-attrs

Вопрос:

Я хотел бы воссоздать свой объект из словаря, используя cattr , но, похоже, это не работает с вложенным полем, установленным в None .

Вот пример кода, который объясняет проблему:

 import attr 
import cattr

@attr.s(auto_attribs=True) 
class B(object):
    b :int = 0

@attr.s(auto_attribs=True) 
class A(object):
    a :int = 0
    b: B = None

x = A(1) 
x_dict  = attr.asdict(x) 
 

Теперь, если я хочу структурировать свой объект с помощью:

 cattr.structure(x_dict,A)
 

Я получаю следующую ошибку:

    if 'b' in o:
TypeError: argument of type 'NoneType' is not iterable
 

Одним из обходных путей является удаление полей None из dict перед вызовом структуры :

 del x_dict["b"]
cattr.structure(x_dict,A) 
 

Нужно ли мне это делать? или есть более простое решение

Мы очень ценим любую помощь.

Комментарии:

1. Является ли использование dataclass вариантом для вас?

2. @balderman спасибо за предложение, но я предпочитаю использовать attrs .

3. Могу ли я поделиться примером dict —> dataclass (включая вложенные объекты). Здесь чисто и прохладно..

4. @balderman, конечно, ты можешь.

5. одна из проблем с dacite заключается в том, что он пытается делать слишком много вещей — например, выполнять проверку типа, которая обычно не нужна. Это также в целом медленнее для де/сериализации, чем в других библиотеках.

Ответ №1:

None не является действительным B . Вы должны определить b , чтобы иметь тип Optional[B] :

 from typing import Optional
import attr
import cattr


@attr.s(auto_attribs=True)
class B(object):
    b: int = 0


@attr.s(auto_attribs=True)
class A(object):
    a: int = 0
    b: Optional[B] = None


x = A(1)
x_dict = attr.asdict(x)
cattr.structure(x_dict, A)
 

Ответ №2:

Ниже представлено решение на основе классов данных

 from dataclasses import dataclass
from typing import List
from dacite import from_dict



@dataclass
class Dog:
    name:str
    age:int

@dataclass
class Person:
    name: str
    dogs: List[Dog] = None


data1 = [{'name':'jack','dogs':[{'name':'bark','age':12},{'name':'jumpy','age':3}]}]
persons1: List[Person] = [from_dict(Person,entry) for entry in data1]
print(persons1)

data2 = [{'name':'jack'}]
persons2: List[Person] = [from_dict(Person,entry) for entry in data2]
print(persons2)
 

выход

 [Person(name='jack', dogs=[Dog(name='bark', age=12), Dog(name='jumpy', age=3)])]
[Person(name='jack', dogs=None)]