buk*_*zor 12 python super getattr getattribute
我正在使用与此代码类似的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()
Run Code Online (Sandbox Code Playgroud)
我希望看到'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
(aka __getattr__),但确实定义了tp_getattro(aka __getattribute__):
PyTypeObject PySuper_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"super", /* tp_name */
...
0, /* tp_getattr */
...
super_getattro, /* tp_getattro */
...
};
Run Code Online (Sandbox Code Playgroud)
(回想一下,__getattribute__被称为每次请求的属性,而不是__getattr__,它如果属性没有对象(大致上不存在只叫:如果属性不在对象
__dict__)).
接下来,查看super_getattro
(aka 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)
Run Code Online (Sandbox Code Playgroud)
这显然为什么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'
Run Code Online (Sandbox Code Playgroud)
这似乎工作正常。我目前不明白为什么标准超类不这样做。
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()
Run Code Online (Sandbox Code Playgroud)