メソッドはどのように__getattribute__
使用されますか?
通常のドット ルックアップの前に呼び出されます。が発生した場合AttributeError
、 を呼び出します__getattr__
。
この方法の使用はかなりまれです。標準ライブラリには 2 つの定義しかありません。
$ grep -Erl "def __getattribute__\(self" cpython/Lib | grep -v "/test/"
cpython/Lib/_threading_local.py
cpython/Lib/importlib/util.py
ベスト プラクティス
単一の属性へのアクセスをプログラムで制御する適切な方法は、property
. クラスD
は次のように記述する必要があります (明らかに意図した動作を再現するために、オプションでセッターとデリータを使用します)。
class D(object):
def __init__(self):
self.test2=21
@property
def test(self):
return 0.
@test.setter
def test(self, value):
'''dummy function to avoid AttributeError on setting property'''
@test.deleter
def test(self):
'''dummy function to avoid AttributeError on deleting property'''
そして使用法:
>>> o = D()
>>> o.test
0.0
>>> o.test = 'foo'
>>> o.test
0.0
>>> del o.test
>>> o.test
0.0
プロパティはデータ記述子であるため、通常のドット ルックアップ アルゴリズムで最初に検索されます。
オプション__getattribute__
を介してすべての属性のルックアップを実装する必要がある場合は、いくつかのオプションがあります__getattribute__
。
- raise
AttributeError
、__getattr__
呼び出されます (実装されている場合)
- それから何かを返す
super
親 (おそらくobject
の) 実装を呼び出すために使用
- 呼び出し
__getattr__
- 何らかの方法で独自のドット ルックアップ アルゴリズムを実装する
例えば:
class NoisyAttributes(object):
def __init__(self):
self.test=20
self.test2=21
def __getattribute__(self, name):
print('getting: ' + name)
try:
return super(NoisyAttributes, self).__getattribute__(name)
except AttributeError:
print('oh no, AttributeError caught and reraising')
raise
def __getattr__(self, name):
"""Called if __getattribute__ raises AttributeError"""
return 'close but no ' + name
>>> n = NoisyAttributes()
>>> nfoo = n.foo
getting: foo
oh no, AttributeError caught and reraising
>>> nfoo
'close but no foo'
>>> n.test
getting: test
20
もともと欲しかったもの。
そして、この例は、最初に望んでいたことをどのように行うかを示しています。
class D(object):
def __init__(self):
self.test=20
self.test2=21
def __getattribute__(self,name):
if name=='test':
return 0.
else:
return super(D, self).__getattribute__(name)
そして、次のように動作します。
>>> o = D()
>>> o.test = 'foo'
>>> o.test
0.0
>>> del o.test
>>> o.test
0.0
>>> del o.test
Traceback (most recent call last):
File "<pyshell#216>", line 1, in <module>
del o.test
AttributeError: test
コードレビュー
コメント付きのコード。で自分自身をドット ルックアップしてい__getattribute__
ます。これが、再帰エラーが発生する理由です。name が"__dict__"
であるかどうかを確認し、回避策として使用できますsuper
が、それはカバーしません__slots__
。それは読者への演習として残しておきます。
class D(object):
def __init__(self):
self.test=20
self.test2=21
def __getattribute__(self,name):
if name=='test':
return 0.
else: # v--- Dotted lookup on self in __getattribute__
return self.__dict__[name]
>>> print D().test
0.0
>>> print D().test2
...
RuntimeError: maximum recursion depth exceeded in cmp