簡體   English   中英

python:__getattr__的合作超級調用

[英]python: cooperative supercall of __getattr__

我正在使用與此代碼類似的somethign:

class BaseClass(object):
    def __getattr__(self, attr):
        return lambda:'1'

class SubClass(BaseClass):
    def foo(self):
        suffix = '2'
        return super(SubClass, self).foo() + suffix

class SubClass2(SubClass):
    def foo(self):
        suffix = '3'
        return super(SubClass2, self).foo() + suffix

o = SubClass2()
print o.foo()

我希望看到'123'的輸出,但我得到一個錯誤AttributeError: 'super' object has no attribute 'foo' Python甚至沒有嘗試使用基類的__getattr__

如果不修改基類,並保持兩個超級調用相似,我就無法獲得我想要的輸出。 有沒有合適的超級電話模式在這里適合我?

我知道super()以某種方式覆蓋getattr以完成它需要做的事情,但我問是否有任何合理的解決方法允許在適當的時候調用子類的__getattr__

啊,這是一個很好的問題!

簡而言之,這里發生的事情是CPython內部在進行屬性查找時偶爾會采用快捷方式,而這種令人驚訝的行為是其中一個后果(另一個是提高性能)。

為了准確了解在這種情況下發生了什么,我們需要冒險進入super的定義: http//hg.python.org/cpython/file/c24941251473/Objects/typeobject.c#l6689

特別注意它沒有定義tp_getattr (又名__getattr__ ),但確實定義了tp_getattro (又名__getattribute__ ):

PyTypeObject PySuper_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "super",                                    /* tp_name */
    ...
    0,                                          /* tp_getattr */
    ...
    super_getattro,                             /* tp_getattro */
    ...
};

(回想一下, 每次請求一個屬性時都會調用__getattribute__ ,而不是__getattr__ ,只有在對象上不存在該屬性時才會調用它(粗略地說:如果該屬性不在對象的__dict__ ))。

接下來,查看super_getattro (又名super.__getattribute__ )的定義,我們可以看到實現大致如下:

class super(object):
    def __init__(self, obj_type, obj):
        self.obj_type = obj_type
        self.obj = obj

    def __getattribute__(self, attr):
        i = self.obj_type.__mro__.find(self.obj_type)
        i += 1
        while i < len(obj_type.__mro__):
            cur_type = self.obj_type.__mro__[i]
            cur_dict = cur_type.__dict___
            res = cur_dict.get(attr)
            if res is not None:
                return res
            i += 1
        return object.__getattribute__(self, attr)

這顯然為什么super不能很好地與__getattr__ - super只檢查父類' __dict__中的屬性!

有趣的是:似乎pypy (從2.1.0開始)的行為方式相同:

$ pypy super.py 
Traceback (most recent call last):
  File "app_main.py", line 72, in run_toplevel
  File "super.py", line 16, in <module>
    print o.foo()
  File "super.py", line 13, in foo
    return super(SubClass2, self).foo() + suffix
  File "super.py", line 8, in foo
    return super(SubClass, self).foo() + suffix
AttributeError: 'super' object has no attribute 'foo'

這似乎工作正常。 我目前沒有看到為什么標准超類不會這樣做。

class super2(super):
    def __getattr__(self, attr):
        return self.__self__.__getattr__(attr)

class BaseClass(object):
    def __getattr__(self, attr):
        return lambda:'1'

class SubClass(BaseClass):
    def foo(self):
        suffix = '2'
        return super2(SubClass, self).foo() + suffix

class SubClass2(SubClass):
    def foo(self):
        suffix = '3'
        return super2(SubClass2, self).foo() + suffix

o = SubClass2()
print o.foo()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM