__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
ため、Pythonは属性'f.__getattribute__('__dict__')
に再度アクセスしようとします。'__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
それは演習として残しておきます。