質問

私は間の違いを理解しようとしています __getattr____getattribute__, しかし、私はそれに失敗しています。

答え スタックオーバーフローの質問に との差 __getattr__ vs __getattribute__ 言う:

__getattribute__ オブジェクト上の実際の属性を調べる前に呼び出されるため、正しく実装するのが難しい場合があります。あなたは無限の再帰に非常に簡単に終わることができます。

それが何を意味するのか全くわかりません。

それからそれは次のように言い続けます:

あなたはほぼ間違いなく欲しいです __getattr__.

なんで?

私はそれを読みました __getattribute__ 失敗する、 __getattr__ 呼ばれています。では、なぜ同じことをする2つの異なる方法があるのですか?私のコードが新しいスタイルのクラスを実装している場合、私は何を使用すればよいですか?

この質問をクリアするためのコード例をいくつか探しています。私は自分の能力を最大限に活用しましたが、私が見つけた答えは問題について徹底的に議論していません。

ドキュメントがある場合は、それを読む準備ができています。

役に立ちましたか?

解決

最初にいくつかの基本。

オブジェクトを使用すると、その属性を処理する必要があります。通常、私たちはします instance.attribute. 。より多くの制御が必要な場合があります(事前に属性の名前がわからない場合)。

例えば、 instance.attribute なります getattr(instance, 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__ 代わりに使用されていました

  1. それは決して実行されなかったでしょう f 持っています a 属性。
  2. それが実行された場合、(あなたが求めたと言ってみましょう f.b)その後、見つけるために呼ばれていなかったでしょう __dict__ すでにそこにあるからです __getattr__ ifの場合にのみ呼び出されます 属性を見つける他のすべての方法は失敗しました.

上記のクラスを使用して書くための「正しい」方法 __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

私はそれを練習として残します。

他の答えは、間の違いを説明する素晴らしい仕事をしたと思います __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__.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top