正确使用super的方式(参数传递)

cha*_*ite 81 python

所以我遵循Python的Super Considered Harmful,然后去测试他的例子.

但是,示例1-3,super在处理__init__期望不同参数的方法时,应该显示正确的调用方式,flat-out不起作用.

这就是我得到的:

~ $ python example1-3.py 
MRO: ['E', 'C', 'A', 'D', 'B', 'object']
E arg= 10
C arg= 10
A
D arg= 10
B
Traceback (most recent call last):
  File "Download/example1-3.py", line 27, in <module>
    E(arg=10)
  File "Download/example1-3.py", line 24, in __init__
    super(E, self).__init__(arg, *args, **kwargs)
  File "Download/example1-3.py", line 14, in __init__
    super(C, self).__init__(arg, *args, **kwargs)
  File "Download/example1-3.py", line 4, in __init__
    super(A, self).__init__(*args, **kwargs)
  File "Download/example1-3.py", line 19, in __init__
    super(D, self).__init__(arg, *args, **kwargs)
  File "Download/example1-3.py", line 9, in __init__
    super(B, self).__init__(*args, **kwargs)
TypeError: object.__init__() takes no parameters
Run Code Online (Sandbox Code Playgroud)

object本身似乎违反了文档中提到的最佳实践之一,即使用的方法super必须接受*args**kwargs.

现在,显然Knight先生期望他的例子可以工作,所以在最近的Python版本中这是改变了吗?我检查了2.6和2.7,两者都失败了.

那么处理这个问题的正确方法是什么?

unu*_*tbu 90

有时两个类可能有一些共同的参数名称.在这种情况下,您无法弹出键值对**kwargs或从中删除键值对*args.相反,您可以定义一个Base不同的类object,吸收/忽略参数:

class Base(object):
    def __init__(self, *args, **kwargs): pass

class A(Base):
    def __init__(self, *args, **kwargs):
        print "A"
        super(A, self).__init__(*args, **kwargs)

class B(Base):
    def __init__(self, *args, **kwargs):
        print "B"
        super(B, self).__init__(*args, **kwargs)

class C(A):
    def __init__(self, arg, *args, **kwargs):
        print "C","arg=",arg
        super(C, self).__init__(arg, *args, **kwargs)

class D(B):
    def __init__(self, arg, *args, **kwargs):
        print "D", "arg=",arg
        super(D, self).__init__(arg, *args, **kwargs)

class E(C,D):
    def __init__(self, arg, *args, **kwargs):
        print "E", "arg=",arg
        super(E, self).__init__(arg, *args, **kwargs)

print "MRO:", [x.__name__ for x in E.__mro__]
E(10)
Run Code Online (Sandbox Code Playgroud)

产量

MRO: ['E', 'C', 'A', 'D', 'B', 'Base', 'object']
E arg= 10
C arg= 10
A
D arg= 10
B
Run Code Online (Sandbox Code Playgroud)

请注意,要使其工作,Base必须是MRO中的倒数第二个类.

  • 不应该`Base`调用`super(Base,self).__ init __()`? (4认同)
  • 为了实现这一点,`Base`必须位于MRO的末尾(除了`object`).调用`object .__ init__`什么都不做,所以不要调用`super(Base,self).__ init __()`.事实上,我认为可能更清楚的是不要包括`super(Base,self).__ init __()`来推动回归"Base"是该行的结尾. (4认同)

jul*_*ria 21

如果你将有很多遗产(在这里就是这种情况),我建议你使用它们**kwargs,然后pop在你使用它们之后立即传递所有参数(除非你需要它们在上层).

class First(object):
    def __init__(self, *args, **kwargs):
        self.first_arg = kwargs.pop('first_arg')
        super(First, self).__init__(*args, **kwargs)

class Second(First):
    def __init__(self, *args, **kwargs):
        self.second_arg = kwargs.pop('second_arg')
        super(Second, self).__init__(*args, **kwargs)

class Third(Second):
    def __init__(self, *args, **kwargs):
        self.third_arg = kwargs.pop('third_arg')
        super(Third, self).__init__(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

这是解决这类问题的最简单方法.

third = Third(first_arg=1, second_arg=2, third_arg=3)
Run Code Online (Sandbox Code Playgroud)

  • 这很好,但是这样就失去了参数的显式性质,例如它们的名称和可能的默认值。有没有办法保留这个明确的部分? (2认同)

Bjö*_*lex 6

正如在Python的super()中所解释的那样,一种方法是让类吃掉它需要的参数,然后传递其余的参数.因此,当调用链到达时object,所有参数都已被吃掉,并且object.__init__将在没有参数的情况下调用(正如它所期望的那样).所以你的代码应该是这样的:

class A(object):
    def __init__(self, *args, **kwargs):
        print "A"
        super(A, self).__init__(*args, **kwargs)

class B(object):
    def __init__(self, *args, **kwargs):
        print "B"
        super(B, self).__init__(*args, **kwargs)

class C(A):
    def __init__(self, arg, *args, **kwargs):
        print "C","arg=",arg
        super(C, self).__init__(*args, **kwargs)

class D(B):
    def __init__(self, arg, *args, **kwargs):
        print "D", "arg=",arg
        super(D, self).__init__(*args, **kwargs)

class E(C,D):
    def __init__(self, arg, *args, **kwargs):
        print "E", "arg=",arg
        super(E, self).__init__(*args, **kwargs)

print "MRO:", [x.__name__ for x in E.__mro__]
E(10, 20, 30)
Run Code Online (Sandbox Code Playgroud)