__getattr__
と__getattribute__
の違いを理解しようとしていますが、失敗しています。
answer Stack Overflowの質問__getattr__
と__getattribute__
の違い言う:
__getattribute__
は、オブジェクトの実際の属性を見る前に呼び出されるため、正しく実装するのは難しい場合があります。あなたは非常に簡単に無限の再帰で終わることができます。
私はそれが何を意味するのか全く分かりません。
それからそれは言い続けます:
ほぼ間違いなく
__getattr__
が必要です。
どうして?
__getattribute__
が失敗すると、__getattr__
が呼び出されることを読みました。では、なぜ同じことを行う2つの異なる方法があるのでしょうか?コードで新しいスタイルクラスを実装する場合、何を使用すればよいですか?
この質問を解決するためのコード例を探しています。私は自分の能力を最大限に活用しましたが、見つけた答えは問題を徹底的に説明していません。
ドキュメントがある場合、それを読む準備ができています。
オブジェクトでは、その属性を処理する必要があります。通常、instance.attribute
を実行します。事前に属性の名前がわからない場合は、さらに制御が必要な場合があります。
たとえば、instance.attribute
はgetattr(instance, attribute_name)
になります。このモデルを使用すると、文字列としてattribute_nameを指定することで属性を取得できます。
__getattr__
の使用また、__getattr__
メソッドを使用して、明示的に管理しない属性を処理する方法をクラスに指示することもできます。
Pythonは、まだ定義されていない属性を要求するたびにこのメソッドを呼び出します。したがって、何をするかを定義できます。
古典的なユースケース:
class A(dict):
def __getattr__(self, name):
return self[name]
a = A()
# Now a.somekey will give a['somekey']
__getattribute__
の使用すべての属性をキャッチする必要がある場合存在するかどうかに関係なく、代わりに__getattribute__
を使用します。違いは、__getattr__
は実際には存在しない属性に対してのみ呼び出されることです。属性を直接設定する場合、その属性を参照すると、__getattr__
を呼び出さずに属性が取得されます。
__getattribute__
は常に呼び出されます。
__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__
メソッド(クラスのMethod Resolution OrderまたはMROの次のクラス)を現在のオブジェクトself
にバインドし、それを呼び出して作業を実行させます。 。
この問題はすべて、属性が見つからないまでPython 通常のことですを許可する__getattr__
を使用することで回避できます。その時点で、Pythonは__getattr__
メソッドに制御を渡し、何かを考え出させます。
また、__getattr__
を使用して無限再帰を実行できることにも注意してください。
class Foo(object):
def __getattr__(self, attr):
return self.attr
これは演習として残しておきます。
他の答えは__getattr__
と__getattribute__
の違いを説明するのに素晴らしい仕事をしたと思いますが、はっきりしないかもしれないことの1つは__getattribute__
を使用する理由です。 __getattribute__
の素晴らしい点は、クラスにアクセスするときにドットをオーバーロードできることです。これにより、低レベルでの属性へのアクセス方法をカスタマイズできます。たとえば、自己引数のみをとるすべてのメソッドがプロパティとして扱われるクラスを定義するとします。
# prop.py
import inspect
class PropClass(object):
def __getattribute__(self, attr):
val = super(PropClass, self).__getattribute__(attr)
if callable(val):
argcount = len(inspect.getargspec(val).args)
# Account for self
if argcount == 1:
return val()
else:
return val
else:
return val
そして、インタラクティブなインタープリターから:
>>> import prop
>>> class A(prop.PropClass):
... def f(self):
... return 1
...
>>> a = A()
>>> a.f
1
もちろんこれはばかげた例であり、おそらくこれを行うことはおそらくないでしょうが、__getattribute__
をオーバーライドすることで得られる力を示しています。