Pythonでは、デコレーター@propertyを使用すると「仮想」属性を作成できます。これは、通常のフィールドのように見え、使用されるメソッドですが、ゲッター、セッター、またはデリータのロジックを実行します。これは、計算されたプロパティを作成したり、データへのアクセスを制御するのに便利です。
例:
class Rectangle: def __init__(self, width, height): self._width = width self._height = height @property def area(self): return self._width * self._height @property def width(self): return self._width @width.setter def width(self, value): if value <= 0: raise ValueError('Width must be positive') self._width = value r = Rectangle(3, 4) print(r.area) # 12(プロパティとして呼び出される、関数ではない) r.width = 10 # セッターが自動的に呼び出される
セッターを定義せずに@property(ゲットメソッド)だけを使用できますか?その属性を変更しようとしたらどうなりますか?
回答: セッター(およびデリータ)を定義せずにゲッター@propertyを定義できます。その場合、その属性は読み取り専用になり、代入しようとするとAttributeErrorが発生します。
class C: @property def x(self): return 42 c = C() c.x = 99 # AttributeError: can't set attribute
逸話
標準ライブラリを使用してオブジェクトをシリアライズしようとしたが、属性の辞書を取得するためにvars(obj)を使用したところ、プロパティメソッドが__dict__の出力に含まれていないことが判明し、値がシリアライズされず、データ漏洩を引き起こした。
逸話
プロジェクトでプロパティのセッターを追加し忘れた結果、計算されたフィールドの値を変更しようとすると、アーキテクチャの論理では予想外の実行時エラーが発生した。
逸話
稼働中のコードで、プロパティの値を計算する際に重いまたは安全でない操作が許可されており、プロパティへのアクセスごとに期待外に呼び出されていた。これによりパフォーマンスが低下し、マルチスレッドコードでブロッキング呼び出しが発生した。