首页 > 解决方案 > super() 可打印表示

问题描述

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

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

whilesuper(B, self).spam给出了一个绑定方法,super(B, B)只适用于类方法,所以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(拉伸)

标签: pythonpython-3.xsuper

解决方案


super()意味着在类方法和常规方法中都有用。在classmethod没有实例的情况下,您只能访问类,因此第二个参数super()接受实例或类。这至少包含在以下文档中super()

如果第二个参数是一个对象,则isinstance(obj, type)必须为真。如果第二个参数是类型,则issubclass(type2, type)必须为真(这对类方法很有用)。

大胆强调我的。

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

  1. 您要用作搜索起点的类(第一个参数)
  2. 从中获取 MRO 的类(如果是实例,则为第二个参数的类型,如果是类,则为第二个参数)。

当您进行属性查找时,还有第三条信息,即属性绑定到的实例或类。这只是第二个参数本身,所以要么是实例,要么是类。repr()输出只反映了前两个值,很大程度上是因为它们是“隐藏的” super(),没有参数,从上下文中获取参数,所以你不能很容易地看到起点是什么,或者 MRO 是什么source 是,但您可以更容易地看到方法的第一个参数(soselfcls)。

如果你想区分你的两个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'>)

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

>>> 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'>)

推荐阅读