В большинстве случаев, когда вы использовали бы __dict__
без dataclasses
, вам, вероятно, следует продолжать использовать __dict__
, возможно, с вызовом copy
. asdict
выполняет лот дополнительной работы, которую вы, возможно, на самом деле не хотите. Вот что он делает.
Во-первых, из документов :
Каждый класс данных преобразуется в набор своих полей в виде пар имя: значение. классы данных, диктовки, списки и кортежи возвращаются в. Например:
@dataclass
class Point:
x: int
y: int
@dataclass
class C:
mylist: List[Point]
p = Point(10, 20)
assert asdict(p) == {'x': 10, 'y': 20}
c = C([Point(0, 0), Point(10, 4)])
assert asdict(c) == {'mylist': [{'x': 0, 'y': 0}, {'x': 10, 'y': 4}]}
Так что если вы хотите рекурсивное диктование класса данных, используйте asdict
. Если вы не хотите этого, то все накладные расходы, связанные с его предоставлением, теряются. В частности, если вы используете asdict
, то изменение реализации содержащихся объектов для использования dataclass
изменит результат asdict
для внешних объектов.
Кроме того, asdict
создает новый dict, в то время как __dict__
просто напрямую обращается к атрибуту объекта dict. Возвращаемое значение asdict
не будет зависеть от переназначения полей исходного объекта. Кроме того, asdict
использует fields
, поэтому, если вы добавите в экземпляр класса данных атрибуты, которые не соответствуют объявленным полям, asdict
не будет включать их.
Наконец, документы вообще не упоминают об этом, но asdict
будет вызывать deepcopy
на всем, что не является объектом класса данных, dict, list или tuple:
else:
return copy.deepcopy(obj)
(Объекты, диктанты, списки и кортежи Dataclass проходят через рекурсивную логику, которая также создает копию, только с применением рекурсивного диктовки.)
deepcopy
действительно дорого сам по себе, и отсутствие какой-либо обработки memo
означает, что asdict
может создать несколько копий общих объектов в нетривиальных графах объектов. Следите за этим:
>>> from dataclasses import dataclass, asdict
>>> @dataclass
... class Foo:
... x: object
... y: object
...
>>> a = object()
>>> b = Foo(a, a)
>>> c = asdict(b)
>>> b.x is b.y
True
>>> c['x'] is c['y']
False
>>> c['x'] is b.x
False