# `dataclasses` --- データクラス

ソースコード: Lib/dataclasses.py

このモジュールは、`__init__()` や `__repr__()` のような special method を生成し、ユーザー定義のクラスに自動的に追加するデコレータや関数を提供します。このモジュールは 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)

  この関数は、後述する special method を生成し、クラスに追加する decorator です。

  `dataclass()` デコレータは、`フィールド` を探すためにクラスを検査します。 `フィールド` は 型アノテーション を持つクラス変数として定義されます。 後述する２つの例外を除き、 `dataclass()` は変数アノテーションで指定した型を検査しません。

  生成されるすべてのメソッドの中でのフィールドの順序は、それらのフィールドがクラス定義に現れた順序です。

  `dataclass()` デコレータは、後述する様々な "ダンダー" メソッド (訳注：dunderはdouble underscoreの略で、メソッド名の前後にアンダースコアが2つ付いているメソッド) をクラスに追加します。クラスに既にこれらのメソッドが存在する場合の動作は、後述する引数によって異なります。デコレータは呼び出した際に指定したクラスと同じクラスを返します。新しいクラスは生成されません。

  `dataclass()` が引数を指定しない単純なデコレータとして使用された場合、ドキュメントに記載されているシグネチャのデフォルト値のとおりに動作します。つまり、以下の３つの `dataclass()` の用例は同等です:

      @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`: (デフォルトの)真の場合、 `__init__()` メソッドが生成されます。

    もしクラスに `__init__()` が既に定義されていた場合は、この引数は無視されます。

  - `repr`: (デフォルトの)真の場合、 `__repr__()` メソッドが生成されます。 生成された repr 文字列には、クラス名、各フィールドの名前および repr 文字列が、クラス上での定義された順序で並びます。 repr から除外するように印が付けられたフィールドは、 repr 文字列には含まれません。 例えば、このようになります: `InventoryItem(name='widget', unit_price=3.0, quantity_on_hand=10)` 。

    もしクラスに `__repr__()` が既に定義されていた場合は、この引数は無視されます。

  - `eq`: (デフォルトの)真の場合、 `__eq__()` メソッドが生成されます。このメソッドはクラスの比較を、そのクラスのフィールドからなるタプルを比較するように行います。比較する2つのインスタンスのクラスは同一でなければなりません。

    もしクラスに `__eq__()` が既に定義されていた場合は、この引数は無視されます。

  - `order`: 真 (デフォルト値は `False`) の場合、 `__lt__()`、`__le__()`、`__gt__()`、`__ge__()` メソッドが生成されます。これらの比較は、クラスをそのフィールドからなるタプルであるかのように取り扱います。比較される2つのインスタンスは、同一の型でなければなりません。もし `order` が true で、 `eq` に falseを指定すすると、`ValueError` が送出されます。

    もし、クラスで既に `__lt__()`, `__le__()`, `__gt__()`, `__ge__()` のうちいずれかが定義されていると `TypeError` が送出されます。

  - `unsafe_hash`: (デフォルトの) `False` の場合、 `eq` と `frozen` がどう設定されているかに従って `__hash__()` メソッドが生成されます。

    `__hash__()` は、組み込みの `hash()` から使われたり、 dict や set のようなハッシュ化されたコレクションにオブジェクトを追加するときに使われます。 `__hash__()` があるということはそのクラスのインスタンスが不変 (イミュータブル) であることを意味します。 可変性というのは複雑な性質で、プログラマの意図、 `__eq__()` が存在しているかどうかとその振る舞い、 `dataclass()` デコレータの `eq` フラグと `frozen` フラグの値に依存します。

    デフォルトでは、 `dataclass()` は追加しても安全でない限り `__hash__()` メソッドを暗黙的には追加しません。 また、明示的に定義され存在している `__hash__()` メソッドに追加したり変更したりはしません。 クラスの属性の `__hash__ = None` という設定は、 Python にとって `__hash__()` のドキュメントにあるような特別な意味があります。

    `__hash__()` が明示的に定義されていなかったり、 `None` に設定されていた場合は、 `dataclass()` は暗黙的に `__hash__()` メソッドを追加する かもしれません 。 推奨はできませんが、 `unsafe_hash=True` とすることで `dataclass()` に `__hash__()` メソッドを作成させられます。 こうしてしまうと、クラスが論理的には不変だがそれにもかかわらず変更できてしまう場合、問題になり得ます。 こうするのは特別なユースケースで、慎重に検討するべきです。

    `__hash__()` メソッドが暗黙的に作られるかどうかを決定する規則は次の通りです。 データクラスに明示的な `__hash__()` メソッドを持たせた上で、 `unsafe_hash=True` と設定することはできません; こうすると `TypeError` になります。

    `eq` と `frozen` が両方とも真だった場合、デフォルトでは `dataclass()` は `__hash__()` メソッドを生成します。 `eq` が真で `frozen` が偽の場合、`__hash__()` は `None` に設定され、(可変なので) ハッシュ化不可能とされます。 `eq` が偽の場合は、 `__hash__()` は手を付けないまま、つまりスーパークラスの `__hash__()` メソッドが使われることになります (スーパークラスが `object` だった場合は、 id に基づいたハッシュ化にフォールバックするということになります)。

  - `frozen`: 真 (デフォルト値は `False`) の場合、フィールドへの代入は例外を生成します。 これにより読み出し専用の凍結されたインスタンスを模倣します。 `__setattr__()` あるいは `__delattr__()` がクラスに定義されていた場合は、 `TypeError` が送出されます。 後にある議論を参照してください。

  - `match_args`: 真なら（デフォルトは `True` ） `__match_args__` タプルは生成された `__init__()` メソッドに渡されたパラメータのリストから作成されます（もし `__init__()` が生成されない場合は上記参照）。もし偽だったり、すでに `__match_args__` がクラスに定義されていた場合には `__match_args__` は生成されません。

  > バージョン 3.10 で追加.

  - `kw_only`: もし真（デフォルトは `False` ）なら、すべてのフィールドはキーワード専用となります。もしフィールドにキーワード専用の指定がされると、 `__init__()` の引数はキーワード専用フィールドから作られ、 `__init__()` 呼び出し時にキーワードを指定しなければならなくなります。このオプションはデータクラスの他の機能には影響はありません。詳細は用語集の parameter を参照してください。もしくは `KW_ONLY` セクションを参照してください。

  > バージョン 3.10 で追加.

  - `slots`: もし真なら（デフォルトは `False` ）、 `__slots__` 属性が作られ、オリジナルのクラスの代わりに新しいクラスが返されます。もし `__slots__` がすでにクラスに定義されていた場合、 `TypeError` が送出されます。

  > バージョン 3.10 で追加.

  `フィールド` には、通常の Python の文法でデフォルト値を指定できます。

      @dataclass
      class C:
          a: int       # 'a' has no default value
          b: int = 0   # assign a default value for 'b'

  この例では、生成された `__init__()` メソッドには `a` と `b` の両方が含まれ、以下のように定義されます:

      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]

  As shown above, the `MISSING` value is a sentinel object used to detect if some parameters are provided by the user. This sentinel is used because `None` is a valid value for some parameters with a distinct meaning. No code should directly use the `MISSING` value.

  `field()` の引数は次の通りです:

  - `default`: 与えられた場合、このフィールドのデフォルト値になります。 これが必要なのは、 `field()` の呼び出しそのものが通常ではデフォルト値がいる位置を横取りしているからです。

  - `default_factory`: 提供されていた場合、0 引数の呼び出し可能オブジェクトでなければならず、このフィールドの初期値が必要になったときに呼び出されます。 他の目的も含めて、下で議論されているように、フィールドに可変なデフォルト値を指定するのに使えます。 `default` と `default_factory` の両方を指定するとエラーになります。

  - `init`: (デフォルトの)真の場合、 生成される `__init__()` メソッドの引数にこのフィールドを含めます。

  - `repr`: (デフォルトの)真の場合、生成される `__repr__()` メソッドによって返される文字列に、このフィールドを含めます。

  - `hash`: これは真偽値あるいは `None` に設定できます。 真の場合、このフィールドは、生成された `__hash__()` メソッドに含まれます。 (デフォルトの) `None` の場合、 `compare` の値を使います: こうすることは普通は期待通りの振る舞いになります。 比較で使われるフィールドはハッシュに含まれるものと考えるべきです。 この値を `None` 以外に設定することは推奨されません。

    フィールドのハッシュ値を計算するコストが高い場合に、 `hash=False` だが `compare=True` と設定する理由が 1 つあるとすれば、フィールドが等価検査に必要かつ、その型のハッシュ値を計算するのに他のフィールドも使われることです。 フィールドがハッシュから除外されていたとしても、比較には使えます。

  - `compare`: (デフォルトの) 真の場合、生成される等価関数と比較関数( `__eq__()` 、`__gt__()` など)にこのフィールドを含めます。

  - `metadata`: これはマッピングあるいは `None` に設定できます。 `None` は空の辞書として扱われます。 この値は `MappingProxyType()` でラップされ、読み出し専用になり、 `Field` オブジェクトに公開されます。 これはデータクラスから使われることはなく、サードパーティーの拡張機構として提供されます。 複数のサードパーティーが各々のキーを持て、メタデータの名前空間として使えます。

  - `kw_only`: もし真なら、このフィールドはキーワード専用となります。これは生成された `__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`(obj, *, dict_factory=dict)

  データクラス `obj` を (ファクトリ関数 `dict_factory` を使い) 辞書に変換します。 それぞれのデータクラスは、 `name: value` という組になっている、フィールドの辞書に変換されます。 データクラス、辞書、リスト、タプルは再帰的に処理されます。 その他のオブジェクトは `copy.deepcopy()` でコピーされます。

  Example of using `asdict()` on nested dataclasses:

      @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}]}

  To create a shallow copy, the following workaround may be used:

      dict((field.name, getattr(obj, field.name)) for field in fields(obj))

  `obj` がデータクラスのインスタンスでなかった場合、 `asdict()` は `TypeError` を送出します。

`dataclasses.``astuple`(obj, *, tuple_factory=tuple)

  データクラス `obj` を (ファクトリ関数 `tuple_factory` を使い) タプルに変換します。 それぞれのデータクラスは、フィールド値のタプルに変換されます。 データクラス、辞書、リスト、タプルは再帰的に処理されます。 その他のオブジェクトは `copy.deepcopy()` でコピーされます。

  1つ前の例の続きです:

      assert astuple(p) == (10, 20)
      assert astuple(c) == ([(0, 0), (10, 4)],)

  To create a shallow copy, the following workaround may be used:

      tuple(getattr(obj, field.name) for field in dataclasses.fields(obj))

  `obj` がデータクラスのインスタンスでなかった場合、 `astuple()` は `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` だけが与えられた場合は、 `typing.Any` が `type` として使われます。 `init`, `repr`, `eq`, `order`, `unsafe_hash`, `frozen`, `match_args`, `kw_only` の値は、 `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`(obj, /, **changes)

  `obj` と同じ型のオブジェクトを新しく作成し、フィールドを `changes` にある値で置き換えます。 `obj` がデータクラスではなかった場合、 `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`(obj)

  引数がデータクラスかデータクラスのインスタンスだった場合に `True` を返します。それ以外の場合は `False` を返します。

  引数がデータクラスのインスタンスである (そして、データクラスそのものではない) かどうかを知る必要がある場合は、 `not isinstance(obj, type)` で追加のチェックをしてください:

      def is_dataclass_instance(obj):
          return is_dataclass(obj) and not isinstance(obj, type)

`dataclasses.``MISSING`

  デフォルト値や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)

  1つのデータクラスの中に、2つ以上の `KW_ONLY` の型のフィールドがあるとエラーになります。

  バージョン 3.10 で追加.

exception `dataclasses.``FrozenInstanceError`

  `frozen=True` 付きで定義されたデータクラスで、暗黙的に定義された `__setattr__()` または `__delattr__()` が呼び出されたときに送出されます。これは `AttributeError` のサブクラスです。

## 初期化後の処理

生成された `__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__()` メソッドを呼びません。もし、ベースクラスが :meth: __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__()` にパラメータを渡す方法を参照してください。 `replace()` が `init=False` であるフィールドをどう取り扱うかについての警告も参照してください。

## クラス変数

One of the few places where `dataclass()` actually inspects the type of a field is to determine if a field is a class variable as defined in PEP 526. It does this by checking if the type of the field is `typing.ClassVar`. If a field is a `ClassVar`, it is excluded from consideration as a field and is ignored by the dataclass mechanisms. Such `ClassVar` pseudo-fields are not returned by the module-level `fields()` function.

## 初期化限定変数

Another place where `dataclass()` inspects a type annotation is to determine if a field is an init-only variable. It does this by seeing if the type of a field is of type `dataclasses.InitVar`. If a field is an `InitVar`, it is considered a pseudo-field called an init-only field. As it is not a true field, it is not returned by the module-level `fields()` function. Init-only fields are added as parameters to the generated `__init__()` method, and are passed to the optional `__post_init__()` method. They are not otherwise used by dataclasses.

例えば、あるフィールドがデータベースから初期化されると仮定して、クラスを作成するときには値が与えられない次の場合を考えます:

    @dataclass
    class C:
        i: int
        j: int | None = None
        database: InitVar[DatabaseType | None] = 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` の `Field` オブジェクトは返しません。

## 凍結されたインスタンス

真に不変な Python のオブジェクトを作成するのは不可能です。 しかし、 `frozen=True` を `dataclass()` デコレータに渡すことで、不変性の模倣はできます。 このケースでは、データクラスは `__setattr__()` メソッドと `__delattr__()` メソッドをクラスに追加します。 これらのメソッドは起動すると `FrozenInstanceError` を送出します。

`frozen=True` を使うとき、実行する上でのわずかな代償があります: `__init__()` でフィールドを初期化するのに単純に割り当てることはできず、 `object.__setattr__()` を使わなくてはなりません。

## 継承

データクラスが `dataclass()` デコレータで作成されるとき、 MRO を逆向きに (すなわち、 `object` を出発点として) 全ての基底クラスを調べていき、見付かったデータクラスそれぞれについて、その基底クラスが持っているフィールドを順序付きマッピングオブジェクトに追加します。 全ての基底クラスのフィールドが追加し終わったら、自分自身のフィールドを順序付きマッピングオブジェクトに追加します。 生成された全てのメソッドは、このフィールドが集められ整列された順序付きのマッピングオブジェクトを利用します。 フィールドは挿入順序で並んでいるので、派生クラスは基底クラスをオーバーライドします。 例えば次のようになります:

    @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=False` を使って) `__init__()` から除外され、かつ、 `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` を共有していることに注意してください。

> データクラスを使っているこのコードが もし仮に 有効なものだとしたら:

>     @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` を使ったさっきの例と同じ問題があります。 すなわち、クラス `D` の 2 つのインスタンスは、クラスインスタンスを作成するときに `x` の具体的な値を指定しておらず、同じ `x` のコピーを共有します。 データクラスは Python の通常のクラス作成の仕組みを使っているだけなので、この同じ問題を抱えています。 データクラスがこの問題を検出する一般的な方法を持たない代わりに、 `dataclass()` デコレータは型が `list` や `dict` や `set` のデフォルトパラメーターを検出した場合、 `TypeError` を送出します。 これは完全ではない解決法ですが、よくあるエラーの多くを防げます。

> デフォルトファクトリ関数を使うのが、フィールドのデフォルト値として可変な型の新しいインスタンスを作成する手段です:

>     @dataclass
>     class D:
>         x: list = field(default_factory=list)

>     assert D().x is not D().x

## Descriptor-typed fields

Fields that are assigned descriptor objects as their default value have the following special behaviors:

- The value for the field passed to the dataclass's `__init__` method is passed to the descriptor's `__set__` method rather than overwriting the descriptor object.

- Similarly, when getting or setting the field, the descriptor's `__get__` or `__set__` method is called rather than returning or overwriting the descriptor object.

- To determine whether a field contains a default value, `dataclasses` will call the descriptor's `__get__` method using its class access form (i.e. `descriptor.__get__(obj=None, type=cls)`. If the descriptor returns a value in this case, it will be used as the field's default. On the other hand, if the descriptor raises `AttributeError` in this situation, no default value will be provided for the field.

    class IntConversionDescriptor:
      def __init__(self, *, default):
        self._default = default

      def __set_name__(self, owner, name):
        self._name = "_" + name

      def __get__(self, obj, type):
        if obj is None:
          return self._default

        return getattr(obj, self._name, self._default)

      def __set__(self, obj, value):
        setattr(obj, self._name, int(value))

    @dataclass
    class InventoryItem:
      quantity_on_hand: IntConversionDescriptor = IntConversionDescriptor(default=100)

    i = InventoryItem()
    print(i.quantity_on_hand)   # 100
    i.quantity_on_hand = 2.5    # calls __set__ with 2.5
    print(i.quantity_on_hand)   # 2

Note that if a field is annotated with a descriptor type, but is not assigned a descriptor object as its default value, the field will act like a normal field.