"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(instance, *, dict_factory=dict)

   データクラスの "instance" を (ファクトリ関数 "dict_factory" を使い)
   辞書に変換します。 それぞれのデータクラスは、 "name: value" という
   組になっている、フィールドの辞書に変換されます。 データクラス、辞書
   、リスト、タプルは再帰的に処理されます。 例えば、次のようになります
   :

      @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" を使い
   ) タプルに変換します。 それぞれのデータクラスは、フィールドの値のタ
   プルに変換されます。 データクラス、辞書、リスト、タプルは再帰的に処
   理されます。

   1つ前の例の続きです:

      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)

   "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(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)


初期化後の処理
==============

生成された "__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

下にある初期化限定変数についての節で、 "__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__()" が呼び出されたときに送出され
   ます。
