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

  この関数は、後述する 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)
      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` が送出されます。 後にある議論を参照してください。

  `フィールド` には、通常の 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, repr=True, hash=None, init=True, compare=True, metadata=None)

  通常の単純なユースケースでは、この他の機能は必要ありません。 しかし、データクラスには、フィールドごとの情報を必要とする機能もあります。 追加の情報の必要性に応えるために、デフォルトのフィールドの値をモジュールから提供されている `field()` 関数の呼び出しに置き換えられます。 例えば次のようになります:

      @dataclass
      class C:
          mylist: list[int] = field(default_factory=list)

      c = C()
      c.mylist += [1, 2, 3]

  上にあるように、 `MISSING` 値は `default` パラメータと `default_factory` パラメータが提供されたかどうかを検出するのに使われる番兵オブジェクトです。 この番兵が使われるのは、 `None` が `default` の有効な値だからです。 どんなコードでも `MISSING` 値を直接使うべきではありません。

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

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

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

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

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

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

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

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

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

  `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` は `field()` の宣言と同じ意味と値を持ちます。

  他の属性があることもありますが、それらはプライベートであり、調べたり、依存したりしてはなりません。

`dataclasses.``fields`(class_or_instance)

  このデータクラスのフィールドを定義する `Field` オブジェクトをタプルで返します。 データクラスあるいはデータクラスのインスタンスを受け付けます。 データクラスやデータクラスのインスタンスが渡されなかった場合は、 `TypeError` を送出します。 `ClassVar` や `InitVar` といった疑似フィールドは返しません。

`dataclasses.``asdict`(obj, *, dict_factory=dict)

  Converts the dataclass `obj` to a dict (by using the factory function `dict_factory`). Each dataclass is converted to a dict of its fields, as `name: value` pairs. dataclasses, dicts, lists, and tuples are recursed into. Other objects are copied with `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))

  `asdict()` raises `TypeError` if `obj` is not a dataclass instance.

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

  Converts the dataclass `obj` to a tuple (by using the factory function `tuple_factory`). Each dataclass is converted to a tuple of its field values. dataclasses, dicts, lists, and tuples are recursed into. Other objects are copied with `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))

  `astuple()` raises `TypeError` if `obj` is not a dataclass instance.

`dataclasses.``make_dataclass`(cls_name, fields, *, bases=(), namespace=None, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False)

  `cls_name` という名前、 `fields` で定義されるフィールド、 `bases` で与えられた基底クラス、 `namespace` で与えられた名前空間付きで初期化されたデータクラスを作成します。 `fields` はイテラブルで、要素が `name`, `(name, type)`, `(name, type, Field)` のうちのどれかです。 単に `name` だけが与えられた場合は、 `typing.Any` が `type` として使われます。 `init`, `repr`, `eq`, `order`, `unsafe_hash`, `frozen` の値は、 `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)

  Creates a new object of the same type as `obj`, replacing fields with values from `changes`. If `obj` is not a Data Class, raises `TypeError`. If values in `changes` do not specify fields, raises `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)

## 初期化後の処理

生成された `__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` であるフィールドをどう取り扱うかについての警告も参照してください。

## クラス変数

`dataclass()` が実際にフィールドの型の検査を行う 2 箇所のうち 1 つは、フィールドが PEP 526 で定義されたクラス変数かどうかの判定です。 その判定はフィールドの型が `typing.ClassVar` かどうかで行います。 フィールドが `ClassVar` の場合、フィールドとは見なされなくなり、データクラスの機構からは無視されます。 そのような `ClassVar` 疑似フィールドは、モジュールレベル関数 `fields()` の返り値には含まれません。

## 初期化限定変数

`dataclass()` が型アノテーションの検査を行うもう 1 つの箇所は、フィールドが初期化限定変数かどうかの判定です。 その判定はフィールドの型が `dataclasses.InitVar` 型であるかどうかで行います。 フィールドが `InitVar` の場合、初期化限定フィールドと呼ばれる疑似フィールドと見なされます。 これは本物のフィールドではないので、モジュールレベル関数 `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` の `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):

## デフォルトファクトリ関数

> `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 の通常のクラス作成の仕組みを使っているだけなので、この同じ問題を抱えています。 データクラスがこの問題を検出する一般的な方法を持たない代わりに、データクラスは型が `list` や `dict` や `set` のデフォルトパラメーターを検出した場合、 `TypeError` を送出します。 これは完全ではない解決法ですが、よくあるエラーの多くを防げます。

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

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

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

## 例外

exception `dataclasses.``FrozenInstanceError`

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