#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)]