【问题标题】:Second parameter of super()?super() 的第二个参数?
【发布时间】:2018-06-26 09:28:37
【问题描述】:

我的一个同事今天写了类似下面的代码,让我看一下,我花了一段时间才发现错误:

class A():                                                                                         
    def __init__(self):                                                         
        print('A')                                                              

class B(A):                                                                     
    def __init__(self):                                                         
        super(B).__init__()                                               

b = B()

这里的问题是B 的构造函数中没有super()self 参数。令我惊讶的是,在这种情况下绝对没有发生任何事情,即没有错误,什么都没有。 super(B) 创建的 super 对象包含什么?作为一个对象,它显然有一个构造函数,所以这就是被调用的对象,但是那个对象与B 有什么关系呢?特别是,为什么这是有效代码并且不会在某处引发异常? super(B) 是一个有实际用途的对象吗?那会是什么?

【问题讨论】:

  • 你使用的是 Python 2 还是 Python 3?
  • super 上的文档指出省略第二个参数会导致它创建一个未绑定的对象
  • 更奇怪的是,调用super(B).__init__() 只能在B(或B 的子类)的方法内部工作。在类外调用 super(B).__init__() 会抛出 RuntimeError: super(): no arguments
  • Here's 一篇关于未绑定超级对象的非常好的文章。

标签: python python-3.x class super


【解决方案1】:

这里的混淆来自这样一个事实:(在类定义上下文中)super() 提供了一个绑定的super 对象,然后将__init__ 委托给它的__self_class__,而super(B) 创建了一个未绑定的super对象,因为它的__self_class__None,所以 委托。

In [41]: class Test(int):
    ...:     def __init__(self):
    ...:         print(super().__self_class__)
    ...:         print(super().__init__)
    ...:         print(super(Test).__self_class__)
    ...:         print(super(Test).__init__)
    ...:

In [42]: Test()
<class '__main__.Test'>
<method-wrapper '__init__' of Test object at 0x10835c9c8>
None
<method-wrapper '__init__' of super object at 0x10835c3c8>

因此,当您调用super(B).__init__() 时,它会创建一个未绑定的super,但随后会立即在其上调用__init__;由于各个链接in this other answer 中描述的魔法,绑定了未绑定的super。没有对它的引用,所以它消失了,但这就是幕后发生的事情。

【讨论】:

    【解决方案2】:

    导致所有这些歧义的唯一原因是“为什么obj = super(B).__init__() 有效?”。那是因为 super(B).__self_class__ 返回 None 并且在这种情况下,您正在调用 None 对象的 __init__,如下所示返回 None:

    In [40]: None.__init__()
    

    关于其余的情况,你可以通过调用super在这两种情况下的基本属性来简单地检查差异:

    In [36]: class B(A):                                                                     
            def __init__(self):                                                         
                    obj = super(B, self)
                    print(obj.__class__)
                    print(obj.__thisclass__)
                    print(obj.__self_class__)
                    print(obj.__self__)
       ....:         
    
    In [37]: b = B()
    <class 'super'>
    <class '__main__.B'>
    <class '__main__.B'>
    <__main__.B object at 0x7f15a813f940>
    
    In [38]: 
    
    In [38]: class B(A):                                                                     
            def __init__(self):                                                         
                    obj = super(B)
                    print(obj.__class__)
                    print(obj.__thisclass__)
                    print(obj.__self_class__)
                    print(obj.__self__)
       ....:         
    
    In [39]: b = B()
    <class 'super'>
    <class '__main__.B'>
    None
    None
    

    对于其余的内容,我建议您仔细阅读文档。 https://docs.python.org/3/library/functions.html#super 和 Raymond Hettinger https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ 的这篇文章。

    此外,如果您想知道为什么 super(B) 在课堂外不起作用,以及为什么在课堂内不带任何参数地调用 super(),您可以阅读 Martijn https://stackoverflow.com/a/19609168/2867928 的综合回答。

    解决方案的简短描述:

    正如@Nathan Vērzemnieks 在 cmets 中所述,您需要调用一次初始化程序才能使 super() 对象工作。原因在于上述链接中解释的新 super 对象的魔力。

    In [1]: class A:
       ...:     def __init__(self):
       ...:         print("finally!")
       ...:
    
    In [2]: class B(A):
       ...:     def __init__(self):
       ...:         sup = super(B)
       ...:         print("Before: {}".format(sup))
       ...:         sup.__init__()
       ...:         print("After: {}".format(sup))
       ...:         sup.__init__()
       ...:
    
    In [3]: B()
    Before: <super: <class 'B'>, NULL>
    After: <super: <class 'B'>, <B object>>
    finally!
    

    【讨论】:

    猜你喜欢
    • 2013-07-08
    • 2018-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    • 1970-01-01
    相关资源
    最近更新 更多