python - 当类型为 'super()' 时 'object' 的行为?

标签 python super

Python website 上找到关于 super() 的文档说它返回一个代理对象,该对象将方法调用委托(delegate)给父类或兄弟类。在 super considered super 找到的信息, how does super() work with multiple inheritance super considered harmful说明实际上使用了 mro 中的下一个方法。我的问题是,如果使用 super(object, self).some_method() 会发生什么?由于 object 通常出现在 mro 列表的末尾,我猜搜索将立即结束,但出现异常。但实际上,似乎调用了代理本身的方法,如 super(object, self).__repr__() 所示,显示了 super 对象本身。我想知道 super()object 的行为是否根本不委托(delegate)方法。 如果是这种情况,我想知道是否有任何可靠的 Material 提到过它,以及它是否适用于其他 Python 实现。

class X(object):
    def __init__(self):
        # This shows [X, object].
        print X.mro()

        # This shows a bunch of attributes that a super object can have.
        print dir(super(object, self))

        # This shows something similar to <super object at xxx>
        print(object, self)

        # This failed with `super() takes at least one argument`
        try:
            super(object, self).__init__()
        except:
            pass

        # This shows something like <super <class 'object'>, <'X' object>>.
        print(super(object, self).__repr__())

        # This shows the repr() of object, like <'X' object at xxx>
        print(super(X, self).__repr__())


if __name__ == '__main__':
    X()

最佳答案

如果 super 在查看要委托(delegate)给的方法解析顺序 (MRO) 时没有找到任何东西(或者如果您正在寻找属性 __class__)它将检查它自己的属性。

因为 object 始终是 MRO 中的最后一个类型(至少据我所知,它始终是最后一个),您有效地禁用了委派并且它将检查 super 实例。


我发现这个问题真的很有趣,所以我查看了 super 的源代码,特别是委托(delegate)部分(super.__getattribute__ (in CPython 3.6.5)),我将它(粗略地)翻译成纯 Python 并附带一些额外的我自己的评论:

class MySuper(object):
    def __init__(self, klass, instance):
        self.__thisclass__ = klass
        self.__self__ = instance
        self.__self_class__ = type(instance)

    def __repr__(self):
        # That's not in the original implementation, it's here for fun
        return 'hoho'

    def __getattribute__(self, name):
        su_type = object.__getattribute__(self, '__thisclass__')
        su_obj = object.__getattribute__(self, '__self__')
        su_obj_type = object.__getattribute__(self, '__self_class__')

        starttype = su_obj_type

        # If asked for the __class__ don't go looking for it in the MRO!
        if name == '__class__':
            return object.__getattribute__(self, '__class__')
        mro = starttype.mro()
        n = len(mro)

        # Jump ahead in the MRO to the passed in class 
        # excluding the last one because that is skipped anyway.
        for i in range(0, n - 1):
            if mro[i] is su_type:
                break
        # The C code only increments by one here, but the C for loop
        # actually increases the i variable by one before the condition
        # is checked so to get the equivalent code one needs to increment
        # twice here.
        i += 2
        # We're at the end of the MRO. Check if super has this attribute.
        if i >= n:
            return object.__getattribute__(self, name)

        # Go up the MRO
        while True:
            tmp = mro[i]
            dict_ = tmp.__dict__
            try:
                res = dict_[name]
            except:
                pass
            else:
                # We found a match, now go through the descriptor protocol
                # so that we get a bound method (or whatever is applicable)
                # for this attribute.
                f = type(res).__get__
                f(res, None if su_obj is starttype else su_obj, starttype)
                res = tmp
                return res

            i += 1
            # Not really the nicest construct but it's a do-while loop
            # in the C code and I feel like this is the closest Python
            # representation of that.
            if i < n:
                continue
            else:
                break

        return object.__getattribute__(self, name)

如您所见,有一些方法可以最终在 super 上查找属性:

  • 如果您正在寻找 __class__ 属性
  • 如果您立即到达 MRO 的末尾(通过将 object 作为第一个参数传递)!
  • 如果 __getattribute__ 在剩余的 MRO 中找不到匹配项。

实际上因为它像 super 一样工作,所以你可以用它代替(至少就属性委托(delegate)而言):

class X(object):
    def __init__(self):
        print(MySuper(object, self).__repr__())

X()

这将从 MySuper.__repr__ 中打印出 hoho。通过插入一些 print 来跟随控制流,随意试验该代码。

I wonder any reliable material ever mentions it and whether it applies to other Python implementations.

我上面所说的是基于我对 CPython 3.6 源代码的观察,但我认为对于其他 Python 版本应该不会有太大的不同,因为其他 Python 实现(通常)遵循 CPython。

其实我也查过:

并且它们都返回 super__repr__

请注意,Python 遵循“我们都是同意的成年人”的风格,所以如果有人费心将这种不寻常 用法形式化,我会感到惊讶。我的意思是谁会尝试委托(delegate)给 object(“最终”父类)的兄弟类或父类的方法。

关于python - 当类型为 'super()' 时 'object' 的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50656716/

相关文章:

Python 2.7 __init__() 恰好接受 2 个参数(给定 3 个)

Python 2 & 3 与 `super` 的兼容性以及在 Py2 中为旧式但在 Py3 中变为新式的类

python - SQLAlchemy 中使用的 "SQL Expression Language"是否支持 IN 运算符?

python - 在Python中从字典中删除一些固定数量的键的快速方法?

Web 编程中的 Python 线程

python - 如何在 scipy.optimize 函数上强制执行更大的步骤?

python - 类对象没有属性tk?

java - 对象的父类(super class)可访问性

python - 当父类有 super() 时,这意味着什么?

java - 在 Java 类型参数中,<? extends E> 仅表示严格的子类型?还是 E 也足够?