python - 带参数的多重继承

标签 python python-2.7 arguments multiple-inheritance

我已经阅读了很多关于继承的内容,但我似乎无法理解为什么这会给我一个错误(使用 Python 2.7.x)。

class A(object):
    def __init__(self, value):
        super(A, self).__init__()
        print 'First %s' % value

class B(object):
    def __init__(self, value):
        super(B, self).__init__()
        print 'Second %s' % value

class Log(A, B):
    def __init__(self, a, b):
        A.__init__(self, a)
        B.__init__(self, b)

        print 'Log'




x = Log(1000, 2222)



// Error: __init__() takes exactly 2 arguments (1 given)
# Traceback (most recent call last):
#   File "<maya console>", line 21, in <module>
#   File "<maya console>", line 13, in __init__
#   File "<maya console>", line 3, in __init__
# TypeError: __init__() takes exactly 2 arguments (1 given) //

最佳答案

前言:我在此处解释 MRO 的尝试非常不足。如果您有 45 分钟的时间,PyCon 2015 的 Raymond Hettinger 的 this talk 会做得更好很多。具体来说,遍历“ sibling ”的想法可能会产生误导。相反,super 调用只是跟随 MRO,(参见 help(Log))。

尽管有反对票,但这实际上是一个很好的问题。

考虑稍作修改的代码:

class A(object):
    def __init__(self, value):
        super(A, self).__init__()
        print 'A got: %s' % value

class B(object):
    def __init__(self, value):
        super(B, self).__init__()
        print 'B got: %s' % value

class Log(A, B):
    def __init__(self, a, b):
        A.__init__(self, a)
        B.__init__(self, b)

        print 'Log'

我们可以毫无问题地创建 A 和 B 的实例:

a = A("aa")  # A got: aa
b = B("bb")  # B got: bb

但是当我们尝试创建一个 Log 实例时,我们得到一个异常:

c = Log(123,456)
Traceback (most recent call last):
  File "temp2.py", line 21, in 
    c = Log(123, 456)
  File "temp2.py", line 13, in __init__
    A.__init__(self, a)
  File "temp2.py", line 3, in __init__
    super(A, self).__init__()
TypeError: __init__() takes exactly 2 arguments (1 given)

To try to figure out what's going on here, we can give a default to the value parameters (I use None):

class A(object):
    def __init__(self, value=None):
        super(A, self).__init__()
        print 'A got: %s' % value

class B(object):
    def __init__(self, value=None):
        super(B, self).__init__()
        print 'B got: %s' % value

class Log(A, B):
    def __init__(self, a, b):
        A.__init__(self, a)
        B.__init__(self, b)

        print 'Log'

现在我们相同的代码运行没有错误:

c = Log(123, 456)
B got: None
A got: 123
B got: 456
Log

But the output might confuse you: Why were 2 B instances created? or Why did specifying parameter defaults matter?

Well, consider the following (again, slightly modified) code:

class A(object):
    def __init__(self, value=None):
        print 'A got: %s' % value
        super(A, self).__init__()

class B(object):
    def __init__(self, value=None):
        print 'B got: %s' % value
        super(B, self).__init__()

class Log(A, B):
    def __init__(self, a, b):
        print("Before A")
        A.__init__(self, a)
        print("Before B")
        B.__init__(self, b)

        print 'Log'

现在,当我们尝试创建我们的 c 对象时:

c = Log(123, 456)

我们得到:

Before A
A got: 123
B got: None
Before B
B got: 456
Log

What's happening here is that super(A, self).__init__() is actually calling B.__init__().

This is because super() will traverse siblings before the parent looking for someone to implement the method.

In this case, it find's B's __init__ method. B's __init__ method then also looks for siblings then parents, but since there are no siblings for B (as defined by the Log class -- which self is an instance of), B's __init__ calls object.__init__ which effectively does nothing.

Put another way (init being shorthand for __init__):

Log.init()
    A.init()
        super(A, self).init()      -->  B.init()
            super(B, self).init()  -->  object.init()
    B.init()
        super(B, self).init()      -->  object.init()

A.init() 中的 super 找到 B.init() 的原因(而不是 object.init( ) 是因为先搜索 sibling 。在self (Log(A,B)) 的上下文中,B 将首先检查,在父类之前。

这不会像您注意到的那样走向另一个方向,因此 B.init() 中的 super 不会 找到A.init(),而是查找 object.init()。同样,这是因为在 Log 的上下文中,B 将在 A 之后被检查,然后是父级类,对象

一些阅读:


编辑:要解决此问题,您可以显式调用父类(super class) __init__,而不是依赖 super():

class A(object):
    def __init__(self, value):
        object.__init__(self)
        print 'First %s' % value

class B(object):
    def __init__(self, value):
        object.__init__(self)
        print 'Second %s' % value

class Log(A, B):
    def __init__(self, a, b):
        A.__init__(self, a)
        B.__init__(self, b)

        print 'Log'

x = Log(1000, 2222)

或者,由于 object.__init__() 实际上什么都不做,您可以简单地将代码重写为:

class A(object):
    def __init__(self, value):
        print 'First %s' % value

class B(object):
    def __init__(self, value):
        print 'Second %s' % value

class Log(A, B):
    def __init__(self, a, b):
        A.__init__(self, a)
        B.__init__(self, b)

        print 'Log'

x = Log(1000, 2222)

两者都会输出(我认为)您所期望的:

First 1000
Second 2222
Log

关于python - 带参数的多重继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29311504/

相关文章:

python - 将 RDD 转换为列联表 : Pyspark

python - 从 Python 脚本使用 POST 发送文件

python 如何改变代码的结尾

python - 处理Python中的记录器错误

python - 在 python 函数中进行分析

python - 范围(1 :len(df)) assigns NaN to last rows in dataframe

java - 传递无参数时 Var args 参数困惑

c++ - 使用类模板需要模板参数

c++ - 为什么我可以将不完整类型的参数传递给函数?

python - 在 python 中导入问题