[解決!Python]データクラスを定義するには解決!Python

dataclassesモジュールのdataclassデコレーターを使って、クラスの定義でさまざまな特殊メソッドを自動的に生成する方法を紹介する。

» 2023年06月20日 05時00分 公開
[かわさきしんじDeep Insider編集部]

この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。

「解決!Python」のインデックス

連載目次

from dataclasses import dataclass

@dataclass
class Person# クラスのフィールド(属性)は型アノテーションを用いて指定
    name: str
    height: float
    weight: float

    def hello(self):
        print(f'hello {self.name}'# メソッドも定義できる

p = Person('kawasaki', 180, 72)
p.hello()  # hello kawasaki

# 文字列化
repr(p)  # "Person(name='kawasaki', height=180, weight=72)"

# 同値性の比較
p2 = Person('isshiki', 190, 78)
print(p == p2)  # False

@dataclass
class Person# フィールドにはデフォルト値を指定可能
    name: str
    height: float = 0
    weight: float = 0

    def hello(self):
        print(f'hello {self.name}')

p = Person('kawasaki')
print(p.height)  # 0

# 生成する特殊メソッドのカスタマイズ
@dataclass(init=False)
class Person:
    name: str
    height: float
    weight: float

    def __init__(self, name='nanashi', height=170, weight=60):
        self.name = name
        self.height = height
        self.weight = weight

    def hello(self):
        print(f'hello {self.name}'# メソッドも定義できる

p = Person(init=False)
print(p)  # Person(name='nanashi', height=170, weight=60)

@dataclass(order=True# インスタンス同士の大小比較を行えるようにする
class Person# クラスのフィールド(属性)は型アノテーションを用いて指定
    name: str
    height: float = 0
    weight: float = 0

    def hello(self):
        print(f'hello {self.name}'# メソッドも定義できる

p0 = Person('kawasaki', 180, 70)
p1 = Person('kawasaki', 178, 72)
if p0 > p1:
    print('p0 is greater than p1')
else:
    print('p0 is lesser than or equal to p1')
# 出力結果:
#


パラメーター 説明
init __init__メソッドを生成するかどうか。デフォルト値はTrue(生成する)
repr __repr__メソッドを生成するかどうか。デフォルト値はTrue(生成する)
eq __eq__メソッドを生成するかどうか。デフォルト値はTrue(生成する)
order __lt__/__le__/__gt__/__ge__メソッドを生成するかどうか。デフォルト値はFalse(生成しない)
unsafe_hash __hash__メソッドを生成するかどうか。デフォルト値はFalse(eqパラメーターとfrozenパラメーターがTrueの場合は__hash__メソッドを生成するが、それ以外のときは生成しない)。Trueなら(仮にそのクラスのインスタンスがイミュータブルでなくとも)__hash__メソッドを生成する
frozen このクラスのインスタンスのフィールド(属性)への代入を許すかどうか。デフォルト値はFalse(代入を許す)
match_args __match_args__属性を作成するかどうか。デフォルト値はTrue(作成する)
kw_only 全てのフィールドをキーワード専用とするかどうか。デフォルト値はFalse(キーワード専用としない)
slots __slots__属性を作成するかどうか。デフォルト値はFalse(作成しない)
weakref_slots __weakref__属性を作成するかどうか。デフォルト値はFalse(作成しない)
dataclassデコレーターのパラメーター

dataclassデコレーターを使ったクラスの定義

 Pythonに標準で添付されるdataclassesモジュールを使うと、クラス定義において自動的に特殊メソッド(__init__メソッド、__repr__メソッドなど)を生成したり、その属性(これをデータクラスについては「フィールド」と呼ぶ)のデフォルト値を可変なものにしたりするためのデコレーターや関数を使用できるようになる。

 dataclassesモジュールにはdataclassデコレーターがあり、これを使うことでクラスの定義を簡単に行える。以下に例を示す。

from dataclasses import dataclass

@dataclass
class Person# クラスのフィールド(属性)は型アノテーションを用いて指定
    name: str
    height: float
    weight: float

    def hello(self):
        print(f'hello {self.name}'# メソッドも定義できる


 データクラスを定義するには「from dataclasses import dataclass」としてdataclassデコレーターをインポートして、これをクラス定義の前に置く(上記コード例の強調書体部分)。

 このクラスのインスタンスが持つフィールド(属性)については型アノテーションを使って指定する。上のコード例ではnameフィールドには文字列を、heightフィールドとweightフィールドには浮動小数点数を指定している。ただし、インスタンス生成時にこれをチェックするわけではない点には注意しよう。

 また、helloメソッドのように通常のメソッドを定義することも可能だ(「データクラス」という名前からはデータを保存するだけで、何かの操作を定義できないように思う人もいるかもしれないがこのデコレーターにより作成されるのは通常のクラスである)。

 インスタンスの生成は通常のクラスと同様だ。

p = Person('kawasaki', 180, 72)
p.hello()  # hello kawasaki


 デコレーターに引数を渡さない場合にはデフォルトで以下の特殊メソッドと属性が追加される。

  • __init__メソッド
  • __repr__メソッド
  • __eq__メソッド
  • __match_args__属性

 そのため、インスタンスの初期化、repr関数(およびこれを使うstr関数)による文字列化、同値性の比較というクラス定義における基本処理の記述を省略できる。

# 文字列化
repr(p)  # "Person(name='kawasaki', height=180, weight=72)"

# 同値性の比較
p2 = Person('isshiki', 190, 78)
print(p1 == p2)  # False


 __repr__メソッドでは上の出力結果のようにインスタンス生成に役立つ形式で文字列化が行われる。もっとシンプルな結果が必要なら、自分で__str__メソッドを定義するようにしよう。

 データクラスのインスタンスのフィールドにデフォルト値を持たせるには次のように型アノテーションでデフォルト値を指定するだけでよい。

@dataclass
class Person# フィールドにはデフォルト値を指定可能
    name: str
    height: float = 0
    weight: float = 0

    def hello(self):
        print(f'hello {self.name}')


Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。