13

このようなクラスがあるかどうか知りたい

class Test(object):
    def __init__(self):
        self.a = 20
        self.b = 30

obj = Test()

私がするときobj.a、どちらが最初に呼び出されますか?

__getattr__またはgetattrまたはルックアップ__dict__['a']

と同じsetattr

Python 2.7 docsによると:

物体。__getattr__ (自己名前)

属性ルックアップで通常の場所に属性が見つからなかった場合に呼び出されます (つまり、インスタンス属性ではなく、self のクラス ツリーにも見つかりません)。name は属性名です。このメソッドは、(計算された) 属性値を返すか、AttributeError 例外を発生させる必要があります。

通常の場所では見られないと言われています。そのいつもの場所は何ですか。いつ呼ばれるか知りたい

また、これとの違いは何ですかobject.__getattribute__(self, name)

すべてが使用されている例を誰か教えてください

4

4 に答える 4

45

少し複雑です。以下は、オブジェクトの属性を要求した場合に Python が行う一連のチェックです。

最初に、Python はオブジェクトのクラスに__getattribute__メソッドがあるかどうかを確認します。定義されていない場合はobject.__getattribute__、属性の値を見つける他の方法を実装するものを継承します。

次のチェックは、オブジェクトのクラスの__dict__. ただし、そこに値が見つかったとしても、属性ルックアップの結果ではない可能性があります。ここで見つかった場合、「データ記述子」のみが優先されます。最も一般的なデータ記述子はpropertyオブジェクトです。これは、属性がアクセスされるたびに呼び出される関数のラッパーです。デコレータを使用してプロパティを作成できます。

class foo(object):
    @property
    def myAttr(self):
        return 2

このクラスでmyAttrは、データ記述子です。__get__これは単純に、とメソッドの両方を使用して記述子プロトコルを実装することを意味し__set__ます。Apropertyはデータ記述子です。

__dict__クラスに要求された名前のものが含まれていない場合はobject.__getattribute__、基本クラスを (MRO に従って) 検索し、継承されているかどうかを確認します。継承されたデータ記述子は、オブジェクトのクラスの記述子と同じように機能します。

データ記述子が見つかった場合、その__get__メソッドが呼び出され、戻り値が属性ルックアップの値になります。データ記述子ではないオブジェクトが見つかった場合、それはしばらく保持されますが、まだ返されません。

次に、オブジェクト自体__dict__の属性がチェックされます。これは、ほとんどの通常のメンバー変数が見つかる場所です。

オブジェクト__dict__が何も持っていなくても、クラス (または基本クラス) の以前の検索でデータ記述子以外の何かが見つかった場合、それが次に優先されます。通常のクラス変数は単純に返されますが、「非データ記述子」はもう少し処理が必要になります。

非データ記述子は、メソッドを持つが__get__メソッドを持たないオブジェクト__set__です。最も一般的な種類の非データ記述子は関数であり、オブジェクトから非データ記述子としてアクセスするとバインドされたメソッドになります (これは、Python がオブジェクトを最初の引数として自動的に渡す方法です)。記述子の__get__メソッドが呼び出され、その戻り値が属性ルックアップの結果になります。

最後に、以前のチェックがどれも成功しなかった場合、__getattr__が呼び出されます (存在する場合)。

親クラスの動作をオーバーライドするために、優先度が徐々に高くなる属性アクセス メカニズムを使用するいくつかのクラスを次に示します。

class O1(object):
    def __getattr__(self, name):
        return "__getattr__ has the lowest priority to find {}".format(name)

class O2(O1):
    var = "Class variables and non-data descriptors are low priority"
    def method(self): # functions are non-data descriptors
        return self.var

class O3(O2):
    def __init__(self):
        self.var = "instance variables have medium priority"
        self.method = lambda: self.var # doesn't recieve self as arg

class O4(O3):
    @property # this decorator makes this instancevar into a data descriptor
    def var(self):
        return "Data descriptors (such as properties) are high priority"

    @var.setter # I'll let O3's constructor set a value in __dict__
    def var(self, value):
        self.__dict__["var"]  = value # but I know it will be ignored

class O5(O4):
    def __getattribute__(self, name):
        if name in ("magic", "method", "__dict__"): # for a few names
            return super(O5, self).__getattribute__(name) # use normal access
        
        return "__getattribute__ has the highest priority for {}".format(name)

そして、動作中のクラスのデモンストレーション:

O1 ( __getattr__):

>>> o1 = O1()
>>> o1.var
'__getattr__ has the lowest priority to find var'

O2 (クラス変数と非データ記述子):

>>> o2 = O2()
>>> o2.var
'Class variables and non-data descriptors are low priority'
>>> o2.method
<bound method O2.method of <__main__.O2 object at 0x000000000338CD30>>
>>> o2.method()
'Class variables and non-data descriptors are low priority'

O3 (ローカルでオーバーライドされたメソッドを含むインスタンス変数):

>>> o3 = O3()
>>> o3.method
<function O3.__init__.<locals>.<lambda> at 0x00000000034AAEA0>
>>> o3.method()
'instance variables have medium priority'
>>> o3.var
'instance variables have medium priority'

O4 (propertyデコレータを使用したデータ記述子):

>>> o4 = O4()
>>> o4.method()
'Data descriptors (such as properties) are high priority'
>>> o4.var
'Data descriptors (such as properties) are high priority'
>>> o4.__dict__["var"]
'instance variables have medium priority'

O5 ( __getattribute__):

>>> o5 = O5()
>>> o5.method
<function O3.__init__.<locals>.<lambda> at 0x0000000003428EA0>
>>> o5.method()
'__getattribute__ has the highest priority for var'
>>> o5.__dict__["var"]
'instance variables have medium priority'
>>> o5.magic
'__getattr__ has the lowest priority to find magic'
于 2013-02-09T11:15:50.267 に答える
1
class test():
    def __init__(self):
        self.a = 1

    def __getattribute__(self, attr):
        print 'Getattribute:',attr

    def __getattr__(self, attr):
        print 'GetAttr:',attr

    def __dict__(self, attr):
        print 'Dict:',attr

    def __call__(self, args=None):
        print 'Called:',args

    def __getitem__(self, attr):
        print 'GetItem:',attr

    def __get__(self, instance, owner):
        print 'Get:',instance,owner

    def __int__(self):
        print 'Int'



x = test()
print x.a

上記のいずれも呼び出されません。

[root@faparch doxid]# python -m trace --trace test_dict.py
 --- modulename: test_dict, funcname: <module>
test_dict.py(1): class test():
 --- modulename: test_dict, funcname: test
test_dict.py(1): class test():
test_dict.py(2):    def __init__(self):
test_dict.py(5):    def __getattribute__(self, attr):
test_dict.py(8):    def __getattr__(self, attr):
test_dict.py(11):   def __dict__(self, attr):
test_dict.py(14):   def __call__(self, args=None):
test_dict.py(17):   def __getitem__(self, attr):
test_dict.py(20):   def __get__(self, instance, owner):
test_dict.py(23):   def __int__(self):
test_dict.py(28): x = test()
 --- modulename: test_dict, funcname: __init__
test_dict.py(3):        self.a = 1
test_dict.py(29): print x.a
1
 --- modulename: trace, funcname: _unsettrace
trace.py(80):         sys.settrace(None)

http://docs.python.org/2/library/numbers.html#numbers.Number おそらく、数値クラス関数を順番に処理するネストされたクラスを実装する必要があります。例のように呼び出しを奪うため。または、少なくともそれはそれを行う1つの方法です。

整数値には、インターセプトする必要のある次の関数が含まれています

['__abs__', '__add__', '__and__', '__class__', '__cmp__', '__coerce__', '__delattr__', '__div__', '__divmod__', '__doc__', '__float__', '__floordiv__', '__format__', '__getattribute__', '__getnewargs__', '__hash__', '__hex__', '__index__', '__init__', '__int__', '__invert__', '__long__', '__lshift__', '__mod__', '__mul__', '__neg__', '__new__', '__nonzero__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'imag', 'numerator', 'real']
于 2013-02-09T11:25:46.343 に答える
0

名前空間の Dictionary( __dict__) が最初に呼び出されます。

からdocs:

クラス インスタンスには、属性参照が検索される最初の場所であるディクショナリとして実装された名前空間があります。そこに属性が見つからず、インスタンスのクラスにその名前の属性がある場合、検索はクラス属性で続行されます。クラス属性が見つからず、オブジェクトのクラスに __getattr__()ルックアップを満たすために呼び出されるメソッドがある場合。

ドキュメントobject.__getattribute__:

クラスのインスタンスの属性アクセスを実装するために無条件に呼び出されます。クラスが も定義している場合__getattr__()、後者は、__getattribute__()明示的に呼び出すか、AttributeError. このメソッドは、(計算された) 属性値を返すか、AttributeError例外を発生させる必要があります。

ドキュメントobject.__getattr__(self, name):

通常のメカニズムで属性が見つかった場合、__getattr__() は呼び出されません。

于 2013-02-09T11:13:28.630 に答える
0

ドキュメントから:

... たとえば、obj.d は obj の辞書で d を検索します。d が method__get__()を 定義している場合、d.__get__(obj)以下に示す優先規則に従って呼び出されます。

... オブジェクトの場合、機械は にobject.__getattribute__()変換b.xされtype(b).__dict__['x'].__get__(b, type(b))ます。実装は、インスタンス変数よりもデータ記述子に優先順位を与え、非データ記述子よりもインスタンス変数に優先順位を与え __getattr__()、提供されている場合は最低の優先順位を割り当てる優先順位チェーンを通じて機能します。

つまり、デフォルトで を使用するobj.a呼び出しです。最終手段と言われています。残りは、たとえば記述子、または通常のメソッドの動作について説明します。__getattribute__()__dict____getattr__()property

メソッドをd定義する方法__get__()

import random 

class C(object):
    @property
    def d(self):
        return random.random()

c = C()
print(c.d)
于 2013-02-09T11:13:49.157 に答える