ProgrammingシニアPython開発者

Pythonにおけるデスクリプタとは何ですか?どのように実装され、何のために使用され、propertyとの違いは何で、使用中によくある誤りは何ですか?

Hintsage AIアシスタントで面接を突破

回答

デスクリプタとは、getset、__delete__のいずれかのメソッドを実装するオブジェクトです。これにより、クラスの属性へのアクセスを制御できます。

デスクリプタの標準メソッド:

  • __get__(self, instance, owner)
  • __set__(self, instance, value)
  • __delete__(self, instance)

デスクリプタには以下の2種類があります:

  • クラシック(データデスクリプタ) — __set__を実装し、通常の属性よりも優先されます;
  • 非クラシック(非データデスクリプタ) — __get__のみを実装し、通常の属性に劣ります。

使用例:

class OnlyPositive: def __init__(self): self._name = '_value' def __get__(self, instance, owner): return instance.__dict__[self._name] def __set__(self, instance, value): if value < 0: raise ValueError('Value must be >= 0') instance.__dict__[self._name] = value class Account: value = OnlyPositive() def __init__(self, value): self.value = value acc = Account(10) acc.value = -1 # ValueError!

propertyはクラスレベルでデスクリプタを作成するための単なる文法的糖衣です。

詰まった質問

デスクリプタをクラスではなくインスタンスの属性として作成した場合、何が起こりますか?

多くの人はデスクリプタが機能すると考えていますが、そうではありません。

正しい答え:

デスクリプタは、クラスの属性として直接定義された場合にのみ機能します。インスタンスの属性としてデスクリプタを設定すると、get/__set__メソッドは呼び出されず、通常の属性へのアクセスの論理が適用されます。

このテーマに関する知られていない繊細さから生じる実際の誤りの例


歴史

完全なデスクリプタの代わりにpropertyを使用

バリデーションやその他の関連属性に対して、開発者は単純なpropertyを使用し、これがロジックの重複と異なるクラス間でのコードの再利用不可能につながっていました。


歴史

ストレージ再利用時の不変性の遵守の不履行

デスクリプタは、インスタンスの内部ストレージではなく、自分のクラスの内部属性(self.x)にデータを保存していたため、属性が「共有」され、異なるインスタンスによって値が上書きされる — オブジェクト間でデータが「漏れ」ました。


歴史

データデスクリプタと非データデスクリプタを混同

複雑な階層で__set__の実装をスキップしたため、インスタンスの通常の属性がデスクリプタを上書きし、バリデーションメカニズム全体が壊れてしまいました — バグは常に現れず、デバッグが難しいものでした。