dataclasses —データクラス
ソースコード: :source: `Lib / dataclasses.py`
このモジュールは、__init__()
や__repr__()
などの生成された特殊メソッドをユーザー定義クラスに自動的に追加するためのデコレータと関数を提供します。 もともとは PEP 557 で説明されていました。
これらの生成されたメソッドで使用するメンバー変数は、 PEP 526 型アノテーションを使用して定義されます。 たとえば、次のコードは次のとおりです。
from dataclasses import dataclass
@dataclass
class InventoryItem:
"""Class for keeping track of an item in inventory."""
name: str
unit_price: float
quantity_on_hand: int = 0
def total_cost(self) -> float:
return self.unit_price * self.quantity_on_hand
特に、次のような__init__()
が追加されます。
def __init__(self, name: str, unit_price: float, quantity_on_hand: int = 0):
self.name = name
self.unit_price = unit_price
self.quantity_on_hand = quantity_on_hand
このメソッドはクラスに自動的に追加されることに注意してください。上記のInventoryItem
定義では直接指定されていません。
バージョン3.7の新機能。
モジュールの内容
- @dataclasses.dataclass(*, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False)
この関数は、以下に説明するように、生成された特殊メソッドをクラスに追加するために使用されるデコレータです。
dataclass()デコレータは、クラスを調べて
field
を見つけます。field
は、型アノテーションを持つクラス変数として定義されます。 以下で説明する2つの例外を除いて、 dataclass()には、変数アノテーションで指定された型を検査するものはありません。生成されたすべてのメソッドのフィールドの順序は、クラス定義に表示される順序です。
dataclass()デコレータは、以下で説明するように、さまざまな「dunder」メソッドをクラスに追加します。 追加されたメソッドのいずれかがクラスにすでに存在する場合、以下に説明するように、動作はパラメーターによって異なります。 デコレータは、呼び出されたのと同じクラスを返します。 新しいクラスは作成されません。
dataclass()がパラメーターのない単純なデコレーターとして使用される場合、この署名に記載されているデフォルト値があるかのように機能します。 つまり、 dataclass()の次の3つの使用法は同等です。
@dataclass class C: ... @dataclass() class C: ... @dataclass(init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False) class C: ...
dataclass()のパラメーターは次のとおりです。
init
:true(デフォルト)の場合、__init__()
メソッドが生成されます。クラスがすでに
__init__()
を定義している場合、このパラメーターは無視されます。repr
:true(デフォルト)の場合、__repr__()
メソッドが生成されます。 生成されたrepr文字列には、クラスで定義されている順序で、クラス名と各フィールドの名前とreprが含まれます。 reprから除外されているとマークされているフィールドは含まれません。 例:InventoryItem(name='widget', unit_price=3.0, quantity_on_hand=10)
。クラスがすでに
__repr__()
を定義している場合、このパラメーターは無視されます。eq
:true(デフォルト)の場合、__eq__()
メソッドが生成されます。 このメソッドは、クラスをそのフィールドのタプルであるかのように順番に比較します。 比較の両方のインスタンスは同じタイプである必要があります。クラスがすでに
__eq__()
を定義している場合、このパラメーターは無視されます。order
:trueの場合(デフォルトはFalse
)、__lt__()
、__le__()
、__gt__()
、および__ge__()
メソッド生成されます。 これらは、クラスをそのフィールドのタプルであるかのように順番に比較します。 比較の両方のインスタンスは同じタイプである必要があります。order
がtrueで、eq
がfalseの場合、 ValueError が発生します。クラスがすでに
__lt__()
、__le__()
、__gt__()
、または__ge__()
のいずれかを定義している場合、 TypeError が発生します。unsafe_hash
:False
(デフォルト)の場合、eq
およびfrozen
の設定方法に従って、__hash__()
メソッドが生成されます。__hash__()
は、組み込みの hash()によって使用され、オブジェクトが辞書やセットなどのハッシュされたコレクションに追加されるときに使用されます。__hash__()
があるということは、クラスのインスタンスが不変であることを意味します。 可変性は、プログラマーの意図、__eq__()
の存在と動作、および dataclass((X178X] dataclass( )デコレータ。デフォルトでは、 dataclass()は、安全でない限り、
__hash__()
メソッドを暗黙的に追加しません。 また、既存の明示的に定義された__hash__()
メソッドを追加または変更することもありません。__hash__()
のドキュメントで説明されているように、クラス属性__hash__ = None
の設定は、Pythonにとって特定の意味を持ちます。__hash__()
が明示的に定義されていない場合、またはNone
に設定されている場合、 dataclass() may は暗黙的な__hash__()
を追加します] 方法。 推奨されていませんが、 dataclass()にunsafe_hash=True
を使用して__hash__()
メソッドを作成させることができます。 これは、クラスが論理的に不変であるにもかかわらず、変更できる場合に当てはまる可能性があります。 これは特殊なユースケースであり、慎重に検討する必要があります。__hash__()
メソッドの暗黙的な作成を管理するルールは次のとおりです。 データクラスに明示的な__hash__()
メソッドを含めることと、unsafe_hash=True
を設定することの両方を行うことはできないことに注意してください。 これにより、 TypeError が発生します。eq
とfrozen
の両方がtrueの場合、デフォルトで dataclass()は__hash__()
メソッドを生成します。eq
がtrueで、frozen
がfalseの場合、__hash__()
はNone
に設定され、ハッシュ不可としてマークされます(つまり、可変であるため)。eq
がfalseの場合、__hash__()
は変更されないままになり、スーパークラスの__hash__()
メソッドが使用されます(スーパークラスがオブジェクトの場合、これはIDベースのハッシュにフォールバックします)。frozen
:trueの場合(デフォルトはFalse
)、フィールドに割り当てると例外が生成されます。 これは、読み取り専用のフリーズされたインスタンスをエミュレートします。__setattr__()
または__delattr__()
がクラスで定義されている場合、 TypeError が発生します。 以下の説明を参照してください。match_args
:trueの場合(デフォルトはTrue
)、__match_args__
タプルは、生成された__init__()
メソッドのパラメーターのリストから作成されます(__init__()
は生成されません。上記を参照してください)。 falseの場合、または__match_args__
がクラスですでに定義されている場合、__match_args__
は生成されません。
バージョン3.10の新機能。
kw_only
:true(デフォルト値はFalse
)の場合、すべてのフィールドがキーワードのみとしてマークされます。 フィールドがキーワードのみとしてマークされている場合、唯一の影響は、__init__()
が呼び出されたときに、キーワードのみのフィールドから生成された__init__()
パラメーターをキーワードとともに指定する必要があることです。 データクラスの他の側面には影響はありません。 詳細については、パラメータの用語集のエントリを参照してください。 KW_ONLY セクションも参照してください。
バージョン3.10の新機能。
slots
:trueの場合(デフォルトはFalse
)、__slots__
属性が生成され、元のクラスの代わりに新しいクラスが返されます。__slots__
がクラスですでに定義されている場合、 TypeError が発生します。
バージョン3.10の新機能。
field
は、通常のPython構文を使用して、オプションでデフォルト値を指定できます。@dataclass class C: a: int # 'a' has no default value b: int = 0 # assign a default value for 'b'
この例では、
a
とb
の両方が、追加された__init__()
メソッドに含まれます。これは次のように定義されます。def __init__(self, a: int, b: int = 0):
TypeError は、デフォルト値のないフィールドがデフォルト値のあるフィールドの後に続く場合に発生します。 これは、これが単一のクラスで発生する場合でも、クラスの継承の結果として発生する場合でも当てはまります。
- dataclasses.field(*, default=MISSING, default_factory=MISSING, init=True, repr=True, hash=None, compare=True, metadata=None, kw_only=MISSING)
一般的で単純なユースケースの場合、他の機能は必要ありません。 ただし、フィールドごとの追加情報を必要とするデータクラス機能がいくつかあります。 この追加情報の必要性を満たすために、デフォルトのフィールド値を、提供されている field()関数の呼び出しに置き換えることができます。 例えば:
@dataclass class C: mylist: list[int] = field(default_factory=list) c = C() c.mylist += [1, 2, 3]
上に示したように、 MISSING 値は、一部のパラメーターがユーザーによって提供されたかどうかを検出するために使用されるセンチネルオブジェクトです。
None
は、明確な意味を持つ一部のパラメーターの有効な値であるため、この歩哨が使用されます。 MISSING 値を直接使用するコードはありません。field()のパラメーターは次のとおりです。
default
:指定されている場合、これがこのフィールドのデフォルト値になります。 field()呼び出し自体がデフォルト値の通常の位置を置き換えるため、これが必要になります。default_factory
:指定されている場合、このフィールドにデフォルト値が必要なときに呼び出される引数なしの呼び出し可能である必要があります。 他の目的の中でも、これは、以下で説明するように、変更可能なデフォルト値を持つフィールドを指定するために使用できます。default
とdefault_factory
の両方を指定するとエラーになります。init
:true(デフォルト)の場合、このフィールドは、生成された__init__()
メソッドのパラメーターとして含まれます。repr
:true(デフォルト)の場合、このフィールドは、生成された__repr__()
メソッドによって返される文字列に含まれます。hash
:これはブール値またはNone
の場合があります。 trueの場合、このフィールドは生成された__hash__()
メソッドに含まれます。None
(デフォルト)の場合は、compare
の値を使用します。これは通常予想される動作です。 フィールドを比較に使用する場合は、ハッシュでフィールドを考慮する必要があります。 この値をNone
以外に設定することはお勧めしません。hash=False
を設定する理由の1つとして、compare=True
は、フィールドのハッシュ値の計算にコストがかかる場合、そのフィールドが等価性テストに必要である場合、およびタイプに寄与する他のフィールドがある場合が考えられます。ハッシュ値。 フィールドがハッシュから除外されている場合でも、比較に使用されます。compare
:true(デフォルト)の場合、このフィールドは、生成された等式および比較メソッド(__eq__()
、__gt__()
など)に含まれます。metadata
:これはマッピングまたはなしの場合があります。 空のdictとして扱われるものはありません。 この値は MappingProxyType()でラップされて読み取り専用になり、 Field オブジェクトで公開されます。 データクラスではまったく使用されず、サードパーティの拡張メカニズムとして提供されます。 複数のサードパーティは、メタデータの名前空間として使用するために、それぞれ独自のキーを持つことができます。kw_only
:trueの場合、このフィールドはキーワードのみとしてマークされます。 これは、生成された__init__()
メソッドのパラメーターが計算されるときに使用されます。
バージョン3.10の新機能。
field()の呼び出しによってフィールドのデフォルト値が指定されている場合、このフィールドのクラス属性は、指定された
default
値に置き換えられます。default
が指定されていない場合、クラス属性は削除されます。 その目的は、 dataclass()デコレータの実行後、デフォルト値自体が指定されているかのように、クラス属性にすべてフィールドのデフォルト値が含まれるようにすることです。 たとえば、次のようになります。@dataclass class C: x: int y: int = field(repr=False) z: int = field(repr=False, default=10) t: int = 20
クラス属性
C.z
は10
、クラス属性C.t
は20
、クラス属性C.x
およびC.y
は設定されません。
- class dataclasses.Field
Field オブジェクトは、定義された各フィールドを記述します。 これらのオブジェクトは内部で作成され、 fields()モジュールレベルのメソッドによって返されます(以下を参照)。 ユーザーは、 Field オブジェクトを直接インスタンス化しないでください。 その文書化された属性は次のとおりです。
name
:フィールドの名前。type
:フィールドのタイプ。default
、default_factory
、init
、repr
、hash
、compare
、metadata
、およびkw_only
は、 field()関数と同じ意味と値を持っています。
他の属性が存在する可能性がありますが、それらは非公開であり、検査または信頼してはなりません。
- dataclasses.fields(class_or_instance)
- このデータクラスのフィールドを定義する Field オブジェクトのタプルを返します。 データクラスまたはデータクラスのインスタンスのいずれかを受け入れます。 データクラスまたはそのインスタンスが渡されない場合、 TypeError を発生させます。
ClassVar
またはInitVar
の疑似フィールドを返しません。
- dataclasses.asdict(instance, *, dict_factory=dict)
データクラス
instance
をdictに変換します(ファクトリ関数dict_factory
を使用)。 各データクラスは、name: value
ペアとして、そのフィールドのdictに変換されます。 データクラス、dict、リスト、およびタプルはに再帰されます。 例えば:@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}]}
instance
がデータクラスインスタンスでない場合、 TypeError を発生させます。
- dataclasses.astuple(instance, *, tuple_factory=tuple)
データクラス
instance
をタプルに変換します(ファクトリ関数tuple_factory
を使用)。 各データクラスは、そのフィールド値のタプルに変換されます。 データクラス、dict、リスト、およびタプルはに再帰されます。前の例からの続き:
assert astuple(p) == (10, 20) assert astuple(c) == ([(0, 0), (10, 4)],)
instance
がデータクラスインスタンスでない場合、 TypeError を発生させます。
- dataclasses.make_dataclass(cls_name, fields, *, bases=(), namespace=None, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False)
cls_name
という名前の新しいデータクラス、fields
で定義されたフィールド、bases
で指定された基本クラスを作成し、namespace
で指定された名前空間で初期化されます。 。fields
は、要素がそれぞれname
、(name, type)
、または(name, type, Field)
のいずれかである反復可能オブジェクトです。name
のみを指定した場合、type
にはtyping.Any
が使用されます。init
、repr
、eq
、order
、unsafe_hash
、frozen
、 [X97X ]、kw_only
、およびslots
は、 dataclass()と同じ意味です。__annotations__
で新しいクラスを作成するPythonメカニズムは、 dataclass()関数を適用して、そのクラスをデータクラスに変換できるため、この関数は厳密には必須ではありません。 この機能は便利なものです。 例えば:C = make_dataclass('C', [('x', int), 'y', ('z', int, field(default=5))], namespace={'add_one': lambda self: self.x + 1})
と同等です:
@dataclass class C: x: int y: 'typing.Any' z: int = 5 def add_one(self): return self.x + 1
- dataclasses.replace(instance, /, **changes)
instance
と同じタイプの新しいオブジェクトを作成し、フィールドをchanges
の値に置き換えます。instance
がデータクラスでない場合、 TypeError が発生します。changes
の値でフィールドが指定されていない場合、 TypeError が発生します。新しく返されるオブジェクトは、データクラスの
__init__()
メソッドを呼び出すことによって作成されます。 これにより、__post_init__()
が存在する場合は、それも呼び出されます。replace()の呼び出しで、デフォルト値のない初期化のみの変数を指定して、
__init__()
および__post_init__()
に渡すことができるようにする必要があります。changes
に、init=False
を持つものとして定義されているフィールドが含まれているとエラーになります。 この場合、 ValueError が発生します。replace()の呼び出し中に、
init=False
フィールドがどのように機能するかについて事前に警告してください。 これらはソースオブジェクトからコピーされるのではなく、初期化されている場合は__post_init__()
で初期化されます。init=False
フィールドは、めったに慎重に使用されないことが予想されます。 それらを使用する場合は、代替クラスコンストラクターを使用するか、インスタンスのコピーを処理するカスタムreplace()
(または同様の名前の)メソッドを使用することをお勧めします。
- dataclasses.is_dataclass(class_or_instance)
パラメータがデータクラスまたはそのインスタンスの場合は
True
を返し、それ以外の場合はFalse
を返します。クラスがデータクラスのインスタンスであるかどうか(データクラス自体ではないかどうか)を知る必要がある場合は、
not isinstance(obj, type)
のチェックをさらに追加します。def is_dataclass_instance(obj): return is_dataclass(obj) and not isinstance(obj, type)
- dataclasses.MISSING
- defaultまたはdefault_factoryが欠落していることを示す番兵値。
- dataclasses.KW_ONLY
型注釈として使用される番兵の値。 タイプが KW_ONLY の疑似フィールドの後のフィールドは、キーワードのみのフィールドとしてマークされます。 タイプ KW_ONLY の疑似フィールドはそれ以外の場合は完全に無視されることに注意してください。 これには、そのようなフィールドの名前が含まれます。 慣例により、 KW_ONLY フィールドには
_
という名前が使用されます。 キーワードのみのフィールドは、クラスがインスタンス化されるときにキーワードとして指定する必要がある__init__()
パラメーターを示します。この例では、フィールド
y
およびz
はキーワードのみのフィールドとしてマークされます。@dataclass class Point: x: float _: KW_ONLY y: float z: float p = Point(0, y=1.5, z=2.0)
単一のデータクラスで、タイプが KW_ONLY である複数のフィールドを指定するとエラーになります。
- exception dataclasses.FrozenInstanceError
frozen=True
で定義されたデータクラスで暗黙的に定義された__setattr__()
または__delattr__()
が呼び出されたときに発生します。 AttributeError のサブクラスです。
初期化後の処理
生成された__init__()
コードは、__post_init__()
がクラスで定義されている場合、__post_init__()
という名前のメソッドを呼び出します。 通常はself.__post_init__()
と呼ばれます。 ただし、InitVar
フィールドが定義されている場合は、クラスで定義された順序で__post_init__()
にも渡されます。 __init__()
メソッドが生成されない場合、__post_init__()
は自動的に呼び出されません。
他の用途の中でも、これにより、1つ以上の他のフィールドに依存するフィールド値を初期化できます。 例えば:
@dataclass
class C:
a: float
b: float
c: float = field(init=False)
def __post_init__(self):
self.c = self.a + self.b
dataclass()によって生成された__init__()
メソッドは、基本クラス__init__()
メソッドを呼び出しません。 基本クラスに呼び出さなければならない__init__()
メソッドがある場合、このメソッドを__post_init__()
メソッドで呼び出すのが一般的です。
@dataclass
class Rectangle:
height: float
width: float
@dataclass
class Square(Rectangle):
side: float
def __post_init__(self):
super().__init__(self.side, self.side)
ただし、派生データクラスはデータクラス自体である基本クラスのすべてのフィールドの初期化を処理するため、通常、データクラスで生成された__init__()
メソッドを呼び出す必要はありません。
__post_init__()
にパラメーターを渡す方法については、initのみの変数に関する以下のセクションを参照してください。 replace()がinit=False
フィールドを処理する方法に関する警告も参照してください。
クラス変数
dataclass()が実際にフィールドの型を検査する2つの場所の1つは、フィールドが PEP 526 で定義されているクラス変数であるかどうかを判別することです。 これは、フィールドのタイプがtyping.ClassVar
であるかどうかを確認することによって行われます。 フィールドがClassVar
の場合、フィールドとしての考慮から除外され、データクラスメカニズムによって無視されます。 このようなClassVar
疑似フィールドは、モジュールレベルの fields()関数によって返されません。
初期化のみの変数
dataclass()が型注釈を検査するもう1つの場所は、フィールドがinitのみの変数であるかどうかを判別することです。 これは、フィールドのタイプがdataclasses.InitVar
タイプであるかどうかを確認することによって行われます。 フィールドがInitVar
の場合、init-onlyフィールドと呼ばれる疑似フィールドと見なされます。 これは真のフィールドではないため、モジュールレベルの fields()関数からは返されません。 初期化専用フィールドは、生成された__init__()
メソッドにパラメーターとして追加され、オプションの__post_init__()
メソッドに渡されます。 それ以外の場合、データクラスでは使用されません。
たとえば、クラスの作成時に値が指定されていない場合、フィールドがデータベースから初期化されるとします。
@dataclass
class C:
i: int
j: int = None
database: InitVar[DatabaseType] = None
def __post_init__(self, database):
if self.j is None and database is not None:
self.j = database.lookup('j')
c = C(10, database=my_database)
この場合、 fields()はi
およびj
に対して Field オブジェクトを返しますが、database
に対しては返しません。
凍結されたインスタンス
真に不変のPythonオブジェクトを作成することはできません。 ただし、frozen=True
を dataclass()デコレータに渡すことで、不変性をエミュレートできます。 その場合、データクラスは__setattr__()
および__delattr__()
メソッドをクラスに追加します。 これらのメソッドは、呼び出されると FrozenInstanceError を発生させます。
frozen=True
を使用すると、パフォーマンスがわずかに低下します。__init__()
は単純な割り当てを使用してフィールドを初期化できないため、 object .__ setattr __()を使用する必要があります。
継承
データクラスが dataclass()デコレータによって作成されている場合、逆MRO(つまり、オブジェクトから開始)でクラスのすべての基本クラスを調べ、データクラスごとに調べます。見つかったものは、その基本クラスのフィールドをフィールドの順序付けられたマッピングに追加します。 すべての基本クラスフィールドが追加された後、順序付けられたマッピングに独自のフィールドが追加されます。 生成されたすべてのメソッドは、フィールドのこの結合され、計算された順序付きマッピングを使用します。 フィールドは挿入順であるため、派生クラスは基本クラスをオーバーライドします。 例:
@dataclass
class Base:
x: Any = 15.0
y: int = 0
@dataclass
class C(Base):
z: int = 10
x: int = 15
フィールドの最終的なリストは、順番にx
、y
、z
です。 x
の最終的なタイプは、クラスC
で指定されているように、int
です。
C
に対して生成された__init__()
メソッドは次のようになります。
def __init__(self, x: int = 15, y: int = 0, z: int = 10):
__init__()のキーワードのみのパラメーターの並べ替え
__init__()
に必要なパラメーターが計算された後、キーワードのみのパラメーターはすべて、すべての通常の(キーワードのみではない)パラメーターの後に移動されます。 これは、Pythonでキーワードのみのパラメーターを実装する方法の要件です。キーワードのみ以外のパラメーターの後に配置する必要があります。
この例では、Base.y
、Base.w
、およびD.t
はキーワードのみのフィールドであり、Base.x
およびD.z
は通常のフィールドです。
@dataclass
class Base:
x: Any = 15.0
_: KW_ONLY
y: int = 0
w: int = 1
@dataclass
class D(Base):
z: int = 10
t: int = field(kw_only=True, default=0)
D
に対して生成された__init__()
メソッドは次のようになります。
def __init__(self, x: Any = 15.0, z: int = 10, *, y: int = 0, w: int = 1, t: int = 0):
パラメータは、フィールドのリストに表示される方法から並べ替えられていることに注意してください。通常のフィールドから派生したパラメータの後に、キーワードのみのフィールドから派生したパラメータが続きます。
キーワードのみのパラメーターの相対的な順序は、並べ替えられた__init__()
パラメーターリストで維持されます。
デフォルトのファクトリ関数
field()が
default_factory
を指定している場合、フィールドのデフォルト値が必要なときに、引数なしで呼び出されます。 たとえば、リストの新しいインスタンスを作成するには、次を使用します。mylist: list = field(default_factory=list)
フィールドが
__init__()
から除外され(init=False
を使用)、フィールドにもdefault_factory
が指定されている場合、デフォルトのファクトリ関数は常に生成された__init__()
から呼び出されます。 ] 関数。 これは、フィールドに初期値を与える他の方法がないために発生します。
変更可能なデフォルト値
Pythonは、デフォルトのメンバー変数値をクラス属性に格納します。 データクラスを使用せずに、次の例を検討してください。
class C: x = [] def add(self, element): self.x.append(element) o1 = C() o2 = C() o1.add(1) o2.add(2) assert o1.x == [1, 2] assert o1.x is o2.x
予想どおり、クラス
C
の2つのインスタンスが同じクラス変数x
を共有していることに注意してください。データクラスを使用して、 if このコードは有効でした。
@dataclass class D: x: List = [] def add(self, element): self.x += element
次のようなコードが生成されます。
class D: x = [] def __init__(self, x=x): self.x = x def add(self, element): self.x += element assert D().x is D().x
これには、クラス
C
を使用した元の例と同じ問題があります。 つまり、クラスインスタンスの作成時にx
の値を指定しないクラスD
の2つのインスタンスは、x
の同じコピーを共有します。 データクラスは通常のPythonクラス作成を使用するだけなので、この動作も共有します。 データクラスがこの状態を検出する一般的な方法はありません。 代わりに、 dataclass()デコレータは、タイプlist
、dict
、または [のデフォルトパラメータを検出すると、 TypeError を発生させます。 X147X]。 これは部分的な解決策ですが、多くの一般的なエラーから保護します。デフォルトのファクトリ関数を使用すると、フィールドのデフォルト値として可変タイプの新しいインスタンスを作成できます。
@dataclass class D: x: list = field(default_factory=list) assert D().x is not D().x