say*_*yap 23 python multiple-inheritance
下面的代码示例,可以super
使用,或者C
有来电A.foo
和B.foo
明确?
class A(object):
def foo(self):
print 'A.foo()'
class B(object):
def foo(self):
print 'B.foo()'
class C(A, B):
def foo(self):
print 'C.foo()'
A.foo(self)
B.foo(self)
Run Code Online (Sandbox Code Playgroud)
Dun*_*can 23
super
确实是出于这种情况,但它只有在你持续使用它时才有效.如果基类也没有全部使用super
它将无法工作,除非方法在object
你必须使用类似公共基类的东西来终止super
调用链.
class FooBase(object):
def foo(self): pass
class A(FooBase):
def foo(self):
super(A, self).foo()
print 'A.foo()'
class B(FooBase):
def foo(self):
super(B, self).foo()
print 'B.foo()'
class C(A, B):
def foo(self):
super(C, self).foo()
print 'C.foo()'
Run Code Online (Sandbox Code Playgroud)
@Marcin问为什么必须有一个共同的基础:
如果没有FooBase
实现,foo
但是没有调用super()
最后一个调用的类super()
将获得属性错误,因为没有基本方法可以调用.
如果有单独的基类class A(AFooBase):
,class B(BFooBase):
并且super()
调用A
将调用该方法AFooBase
,则B
永远不会调用方法.当基类对于所有类都是通用的时,它会转到方法解析顺序的末尾,并且您可以确定无论如何定义类,基类方法都将是最后一个调用的方法.
Ray*_*Luo 18
感谢所有为此主题做出贡献的人.
(当前)接受的答案是不准确的.正确的描述应该是:super()不仅对解析单继承有好处,而且还有多重继承.其原因在@blckknght的评论中得到了很好的解释:
虽然显式调用基类方法可以用于非常简单的场景,例如提问者的示例,但如果基类本身从公共库继承并且您不希望最终基类的方法被调用两次,它将会崩溃.这被称为"钻石继承",对于许多多继承系统来说这是一个大问题(比如在C++中).Python的协作多重继承(使用super())可以让你在很多情况下轻松解决它(虽然这并不是说合作的多继承层次结构很容易设计或总是一个好主意).
正如@duncan指出的那样,正确的方法是使用super(),但要始终如一地使用它.
super
确实是出于这种情况,但它只有在你持续使用它时才有效.如果基类也没有全部使用super
它将无法工作,除非方法在object
你必须使用类似公共基类的东西来终止super
调用链.
class FooBase(object):
def foo(self): pass
class A(FooBase):
def foo(self):
super(A, self).foo()
print 'A.foo()'
class B(FooBase):
def foo(self):
super(B, self).foo()
print 'B.foo()'
class C(A, B):
def foo(self):
super(C, self).foo()
print 'C.foo()'
C().foo() # Run this
Run Code Online (Sandbox Code Playgroud)
但是值得指出的是,调用顺序的方法在初看时可能看起来并不直观.结果是:
B.foo()
A.foo()
C.foo()
Run Code Online (Sandbox Code Playgroud)
这看似奇怪的顺序实际的通话顺序仍然C, A, B
是基于MRO的.换一种说法,
super()
将在"第一个""下一个"超级类上调用foo方法.这基于类的方法解析Order(__mro__
)C
.- 引用和修改@ Manoj-Govindan的回答
>>> C.__mro__
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>)
>>>
Run Code Online (Sandbox Code Playgroud)根据经验,如果您想要返回所有父方法但不关心调用顺序,请谨慎使用super()
.否则,您可以选择以特定顺序显式调用父方法.
不要混合使用super()和显式调用.否则你会得到像这个答案中提到的令人讨厌的重复.
简而言之,super(...)
在整个班级中使用一致性将确保按照MRO的顺序从祖先调用一次所有同名方法.如果方法碰巧是a ,这样的call-ALL-ancestors(而不是call-only-first-candidate)行为可能在概念上更容易接受,参见本博文中的示例.__init__()
然而,说"遵循MRO命令"可能不是很精确.它实际上始终遵循"孙子"的MRO,不知何故.看到它的实际效果令人着迷.以下程序的结果可能与您的想法不完全相同.注意如何A.__mro__
保持在2个不同的调用堆栈相同,但如何super(A, self).name
或super(A, self).foo()
何时被触发不同的行为A().foo()
和通过C().foo()
.查看最后引用的结果.
class FooBase(object):
name = "FooBase"
def foo(self):
print(' Base.foo() begins')
print(" My name is: %s" % self.name)
print(" My super's name is not available")
print(' Base.foo() ends')
class A(FooBase):
name = "A"
def foo(self):
print(' A.foo() begins')
print(" My name is: %s" % self.name)
print(" My super's name is: %s" % super(A, self).name)
print(" A.__mro__ is %s" % str(A.__mro__))
super(A, self).foo()
print(' A.foo() ends')
class B(FooBase):
name = "B"
def foo(self):
print(' B.foo() begins')
print(" My name is: %s" % self.name)
print(" My super's name is: %s" % super(B, self).name)
print(" B.__mro__ is %s" % str(B.__mro__))
super(B, self).foo()
print(' B.foo() ends')
class C(A, B):
name = "C"
def foo(self):
print 'C.foo() begins'
print("My name is: %s" % self.name)
print("My super's name is: %s" % super(C, self).name)
print(" C.__mro__ is %s" % str(C.__mro__))
super(C, self).foo()
print('C.foo() ends')
print("We will call A.foo()")
A().foo()
print("We will call C.foo()")
C().foo() # Run this to see how each foo() is called ONLY ONCE
Run Code Online (Sandbox Code Playgroud)
它的Python 2.7.12的结果是:
We will call A.foo()
A.foo() begins
My name is: A
My super's name is: FooBase
A.__mro__ is (<class '__main__.A'>, <class '__main__.FooBase'>, <type 'object'>)
Base.foo() begins
My name is: A
My super's name is not available
Base.foo() ends
A.foo() ends
We will call C.foo()
C.foo() begins
My name is: C
My super's name is: A
C.__mro__ is (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.FooBase'>, <type 'object'>)
A.foo() begins
My name is: C
My super's name is: B
A.__mro__ is (<class '__main__.A'>, <class '__main__.FooBase'>, <type 'object'>)
B.foo() begins
My name is: C
My super's name is: FooBase
B.__mro__ is (<class '__main__.B'>, <class '__main__.FooBase'>, <type 'object'>)
Base.foo() begins
My name is: C
My super's name is not available
Base.foo() ends
B.foo() ends
A.foo() ends
C.foo() ends
Run Code Online (Sandbox Code Playgroud)
Amb*_*ber 10
super()
只会解析给定方法的单个类类型,因此如果您从多个类继承并想要在两个类中调用该方法,则需要明确地执行此操作.即A.foo(self)
Super将foo
在"第一"超类上调用该方法.这基于类的方法解析Order(__mro__
)C
.
>>> C.__mro__
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>)
>>>
Run Code Online (Sandbox Code Playgroud)
因此,如果你打电话super(C, self).foo()
,A.foo
就叫.如果您将继承顺序更改为class C(B, A):
然后这是相反的.在__mro__
现在看起来像:
>>> C.__mro__
(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>)
>>>
Run Code Online (Sandbox Code Playgroud)
如果您super(C, self).foo()
在进行此更改后致电,B.foo()
则会被致电.
如果添加以下内容:
class A(object):
def foo(self):
print 'A.foo()'
class B(object):
def foo(self):
print 'B.foo()'
class C(A, B):
def foo(self):
super(C, self).foo()
print 'C.foo()'
A.foo(self)
B.foo(self)
c = C()
c.foo()
Run Code Online (Sandbox Code Playgroud)
然后super(C,self).foo()指的是A.foo
输出是
A.foo()
C.foo()
A.foo()
B.foo()
Run Code Online (Sandbox Code Playgroud)
[编辑:包含其他信息和链接]