python:__getattr__ 的协作 super 调用

标签 python super getattr getattribute

我正在使用类似于此代码的东西:

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 调用相似,我无法获得我想要的输出。是否有适合我的合作 super 调用模式?

我知道 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'

关于python:__getattr__ 的协作 super 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18413262/

相关文章:

python - PyAudio stream_callback 意外参数

python - 创建一个空字典,键是可变维度的元组

python - 如何将 super() 与一个参数一起使用?

javascript - this._super() 与 this.super()

java - 在Java多态性中,所有实现接口(interface)的类都可以创建为该类型接口(interface)吗?

python - 如何访问对象中的私有(private)变量

python - PANDAS 棘手的分组方法是在单个列的列表中使用多个组

python - 通过继承共享基础对象

带有字符串的Python多级getattr

Python __getattr__ 'NoneType' 对象不可调用