super() 可打印表示

super() printable representation

sup = super(B, self)sup2 = super(B, B) 具有无法区分的表示,它们看起来都是这样的:

<super: <class 'B'>, <B object>>

虽然 super(B, self).spam 给出了绑定方法,但 super(B, B) 仅适用于 class 方法,因此 super(B, B).cls_spam(),如下所示。你不能将它用于常规方法,你得到一个正常的功能:

class A:
    @classmethod
    def cls_spam(cls):
        print('A.cls_spam: cls =', cls)

    def spam(self):
        print('A.spam: self =', self)

class B(A):
    def call_spam(self):
        sup = super(B, self)
        print('B.call_spam: sup =', sup)
        print('B.call_spam: sup.spam =', sup.spam)
        print('B.call_spam: sup.cls_spam =', sup.cls_spam)
        sup.spam()
        sup.cls_spam()

        sup2 = super(B, B)
        print('B.call_spam: sup2 =', sup2)
        print('B.call_spam: sup2.css_spam =', sup2.cls_spam)
        # can't call sup2.spam(), not without giving it self explicitly
        sup2.cls_spam()

以下互动环节说明:

>>> b = B()
>>> b.call_spam3()
B.call_spam: sup = <super: <class 'B'>, <B object>>
B.call_spam: sup.spam = <bound method A.spam of <__main__.B object at 0x108830b50>>
B.call_spam: sup.cls_spam = <bound method A.cls_spam of <class '__main__.B'>>
A.spam: self = <__main__.B object at 0x108830b50>
A.cls_spam: cls = <class '__main__.B'>
B.call_spam: sup2 = <super: <class 'B'>, <B object>>
B.call_spam: sup2.css_spam = <bound method A.cls_spam of <class '__main__.B'>>
A.cls_spam: cls = <class '__main__.B'>

super() 是一个复杂的主题,如果上述行为被记录在案,理解它会对我有很大帮助。

使用 Python 3.5.3,Debian GNU/Linux 9.11(延伸)

super() 意味着在 class 方法和常规方法中都有用。在 classmethod 中没有实例,您只能访问 class,因此 super() 的第二个参数接受实例或 class。至少在 documentation for super():

If the second argument is an object, isinstance(obj, type) must be true. If the second argument is a type, issubclass(type2, type) must be true (this is useful for classmethods).

大胆强调我的。

现在,super() 必须执行的主要任务是在给定起点的情况下,沿着 classes 的方法解析顺序 (MRO) 列表搜索属性。起点是第一个参数,但MRO必须从第二个参数中获取;如果您在 class Foo 中使用 super(),您当时无法知道 Foo 是否已被 subclassed,这可能会改变 MRO第二个参数。因此,为此目的,super() 跟踪两条信息:

  1. 您想用作搜索起点的class(第一个参数)
  2. 从中获取 MRO 的 class(第二个参数的类型,如果它是一个实例,或者只是第二个参数,如果它是一个 class)。

还有第三条信息,当您进行属性查找时,属性绑定到的实例或 class。这只是第二个参数本身,所以要么是一个实例,要么是 class。 repr() 输出仅反映 前两个值 ,在很大程度上是因为它们是 'hidden',因为 super() 没有参数,从上下文,所以你不能 as easily 查看起点是什么,或者 MRO 源是什么,但是你可以更容易地看到方法的第一个参数(所以selfcls).

如果您想区分您的两个 super() 实例,您可以查看 __self__ 属性,它代表第三条信息:

>>> sup = super(B, b)
>>> sup.__self__
<__main__.B object at 0x108b4c520>
>>> sup2 = super(B, B)
>>> sup2.__self__
<class '__main__.B'>

您在 repr() 输出中看到的另外两条信息分别是 __thisclass____self_class__ 属性:

>>> sup.__thisclass__, sup.__self_class__
(<class '__main__.B'>, <class '__main__.B'>)

当您使用不同的 class 作为第一个参数时,这更容易发现:

>>> sup_a = super(A, b)
>>> sup_a
<super: <class 'A'>, <B object>>
>>> sup_a.__thisclass__, sup_a.__self_class__
(<class '__main__.A'>, <class '__main__.B'>)