__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
練習問題として残しておきます。