13

Pythonのドキュメントによると、

__set__()およびdefinedを持つデータ記述子__get__()は、インスタンス ディクショナリの再定義を常にオーバーライドします。

私はこの文を理解するのに問題はありませんが、なぜそのような規則が設けられているのかを説明してもらえますか? 結局のところ、インスタンス ディクショナリ内の属性をオーバーライドしたい場合は、(通常) インスタンス ディクショナリ内の属性をオーバーライドしないディスクリプタのメソッドを呼び出すため、既に明示的に( inst.__dict__["attr"] = val)行う必要があります。inst.attr = val__set__

編集:明確にするために、何が起こっているのか理解しています。私の質問は、なぜそのようなルールが導入されたのかについてです。

4

1 に答える 1

10

オーバーライドは、クラス __dict__の一部である記述子に適用されます。

Python は常にを検索しtype(instance).__dict__[attributename].__get__(instance, type(instance))、インスタンス オーバーライドの検索には使用しません。instance.__dict__

以下は、不自然Descriptorなクラスとプロパティ ( a__get__と aを持つ記述子) を使用した例__set__です。

>>> class Descriptor(object):
...     def __init__(self, name):
...         self.name = name
...     def __get__(self, instance, cls):
...         print 'Getting %s, with instance %r, class %r' % (self.name, instance, cls)
... 
>>> class Foo(object):
...     _spam = 'eggs'
...     @property
...     def spam(self):
...         return self._spam
...     @spam.setter
...     def spam(self, val):
...         self._spam = val
... 
>>> Foo().spam
'eggs'
>>> foo = Foo()
>>> foo.__dict__['spam'] = Descriptor('Override')
>>> foo.spam
'eggs'

ご覧のとおりspam、インスタンスにエントリを追加しても__dict__、それは完全に無視され、Foo.spamプロパティは引き続き使用されます。プロパティが との両方を定義して__dict__いるため、Python はインスタンスを無視しています。spam__get____set__

a を定義していない記述子を使用すると__set__、オーバーライドが機能します (ただし、__get__呼び出されません:

>>> class Foo(object):
...     desc = Descriptor('Class-stored descriptor')
... 
>>> Foo.desc
Getting Class-stored descriptor, with instance None, class <class '__main__.Foo'>
>>> Foo().desc
Getting Class-stored descriptor, with instance <__main__.Foo object at 0x1018df510>, class <class '__main__.Foo'>
>>> foo = Foo()
>>> foo.__dict__['desc'] = Descriptor('Instance-stored descriptor')
>>> foo.desc
<__main__.Descriptor object at 0x1018df1d0>
于 2012-10-22T08:09:51.037 に答える