Python attrs入門:高機能データクラスを実践例でマスター
attrsのインストール
attrsパッケージは標準ライブラリに含まれていないため、pip installコマンド等でインストールする必要があります。Pipenvのようなツールも使えます。他のプロジェクトに干渉しないよう、仮想環境を作成するのが望ましいです。パッケージ名はattrsなので、インストールは以下のようになります:
$ pip install attrs
# またはpipenvの場合:
$ pipenv install attrs
attrs vs データクラス
attrsの作者たちは、実はデータクラスをPythonに導入したPEPの策定に携わっています。Python標準のデータクラスは意図的にシンプルで理解しやすく保たれていますが、attrsはあなたが欲しいかもしれない全機能を提供します!
Python標準データクラスではなくattrsを選ぶ理由のいくつか:
- Python 3.7より前のバージョンを使用している。attrsはCPython 2.7とPyPyを含むすべてのメインストリームPythonバージョンをサポート。
- より多くの機能が欲しい:attrsはバリデーターとコンバーターを提供。
- 最適なパフォーマンスと最小メモリ使用が欲しい:attrsスロットクラスを使用。
基本的なattrs例
まずは非常に基本的な例を見てみましょう:
import attr
@attr.s
class Person(object):
name = attr.ib(default='John')
surname = attr.ib(default='Doe')
age = attr.ib(init=False)
p = Person()
print(p)
p = Person('Bill', 'Gates')
p.age = 60
print(p)
# 出力:
# Person(name='John', surname='Doe', age=NOTHING)
# Person(name='Bill', surname='Gates', age=60)
いくつかの観察点:
- 構文はデータクラスより冗長でエレガントさに欠けるが、その分エクストラ機能が得られる。
- データクラス同様、print時にデータの整形された表現が得られる。
- attrsパッケージは
attr.ibのような賢い名前を使うため、import attrだけで済む。別途from attr import attrib, attrsとしてフルネームをインポートすることも可能。機能は同じ。
それでは、通常のデータクラスにはない、このパッケージの最も重要な機能であるバリデーターとコンバーターを見ていきましょう。
attrsバリデーター例
attrsデータクラスにバリデーターを追加する方法は2つあります:
- デコレーターを使用
- 呼び出し可能な関数を提供
ここではまず呼び出し可能関数の方法を実演します。attrsにはいくつかの組み込みバリデーターがあり、ここではinstance_ofバリデーターを使用します:
>>> @attr.s
... class C(object):
... x = attr.ib(validator=attr.validators.instance_of(int))
>>> C(42)
C(x=42)
>>> C("a string")
Traceback (most recent call last):
...
TypeError: ("'x' must be <type 'int'> (got 'a string' that is a <type 'str'>).", ...
xに文字列値でオブジェクトCを作成しようとしたため、instance_ofバリデーターがエラーを投げました。int型が必要なのにstr型が渡されたためです。
では、独自バリデーターを定義してみましょう:
import attr
@attr.s
class DividableByTwo(object):
x = attr.ib()
@x.validator
def check(self, attribute, value):
if value % 2 != 0:
raise ValueError(f'{value} is not dividable by 2')
print(DividableByTwo(60))
print(DividableByTwo(11))
# 出力は以下のような感じ:
# DividableByTwo(x=60)
# ...
# ValueError: 11 is not dividable by 2
attrsコンバーター例
コンバーターは設定される値を受け取り、自動的に変換します。あらゆる用途に使えます。例として、値を自動的にintに変換するケースを見てみましょう。ここでも呼び出し可能関数、この場合はPythonのint()関数をそのまま使います:
import attr
@attr.s
class C(object):
x = attr.ib(converter=int)
c = C("1")
print(c)
# 出力:
# C(x=1)
入力(文字列「1」)が自動的に整数に変換されました。コンバーターはバリデーターより前に実行されるため、変換後の最終値をバリデートできます。例えば、上記2例を組み合わせて、まず任意の入力をintに変換し、その後2で割り切れるかチェックするといったことが可能です。
attrsでスロットを使用
最後に、attrsにスロットクラスを使用させることができます。スロットクラスは通常クラスに比べていくつかの利点があります:
- メモリフットプリントが小さい
- 高速
簡単に言えば、スロットクラスではオブジェクトインスタンスが持つと期待するインスタンス属性を明示的に宣言します。これによりPythonはいくつかのチェック等を省略でき、メモリ使用量削減とわずかな高速化につながります。詳細はattrsドキュメントを参照してください。
しかしスロットクラスには注意点もあり、特に手動作成時は顕著です。幸い、attrsはこの機能をシンプルに有効化する方法を提供しています:
import attr
@attr.s(slots=True)
class YourClassName:
...
学びを続ける
- Pythonデータクラスに関する記事
- Pythonクラスとオブジェクトに関するチュートリアル
- 更なる例はattrs例ページを参照
Python
- Python データ型マスター: 実践ガイド
- Python strip()メソッド完全ガイド:実践例付き
- Python str.count()マスター:文字と部分文字列のカウント実例集
- Python round()関数を実例で徹底解説
- Python map()関数をマスター:構文、例、ベストプラクティス
- Python timeit():実行時間測定の実例付きガイド
- Python collections.Counter:効率的なカウント、更新、演算操作
- Python time.sleep():コードに遅延を追加する方法(例付き)
- Python list.count() 完全ガイド:実践例付きで徹底解説
- Python list.index():要素の位置を検索する実践ガイド
- Python C拡張プログラミング:高速ネイティブモジュールの構築