[英]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.