__getattribute__ 属性アクセスが発生するたびに呼び出されます。
class Foo(object):
def __init__(self, a):
self.a = 1
def __getattribute__(self, attr):
try:
return self.__dict__[attr]
except KeyError:
return 'default'
f = Foo(1)
f.a
これは無限再帰を引き起こします。ここで犯人は行return self.__dict__[attr]です。すべての属性が保存されてself.__dict__おり、名前で使用できるとしましょう(真実に十分に近い)。この線
f.a
のa属性へのアクセスを試みますf。これはを呼び出しますf.__getattribute__('a')。__getattribute__その後、ロードを試みますself.__dict__。はの__dict__属性でself == fあり、そのためf.__getattribute__('__dict__')、属性へのアクセスを再試行するpython呼び出し'__dict__'です。これは無限再帰です。
__getattr__代わりに使用されていた場合
- 属性
fがあるため、実行されることはありませんa。
- 実行された場合(要求したとしましょ
f.bう)、それは__dict__既に存在していて、属性を検索する他のすべてのメソッドが失敗した__getattr__場合にのみ呼び出されるため、検索のために呼び出されていません。
上記のクラスを使用して書く「正しい」方法__getattribute__は
class Foo(object):
# Same __init__
def __getattribute__(self, attr):
return super(Foo, self).__getattribute__(attr)
super(Foo, self).__getattribute__(attr)__getattribute__「最も近い」スーパークラス(正式には、クラスのメソッド解決順序、またはMROの次のクラス)のメソッドを現在のオブジェクトにバインドし、selfそれを呼び出して、それを機能させます。
この問題はすべて、属性が見つからなくなるまで__getattr__Pythonに通常の動作をさせることで回避できます。その時点で、Pythonは__getattr__メソッドに制御を渡して、何かを考え出させます。
また、を使用して無限再帰を実行できることにも注意してください__getattr__。
class Foo(object):
def __getattr__(self, attr):
return self.attr
練習問題として残しておきます。