使用以下代码示例,可以使用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)
答案 0 :(得分:21)
super
确实适用于这种情况,但只有在您持续使用它时才有效。如果基类也没有全部使用super
它将无法工作,除非方法在object
中,否则你必须使用类似公共基类的东西来终止{{1}的链调用。
super
@Marcin问为什么必须有一个共同的基础:
如果没有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()'
实现FooBase
但没有调用foo
,那么调用super()
的最后一个类将会出现属性错误,因为没有基本方法可以调用
如果有单独的基类super()
和class A(AFooBase):
,则class B(BFooBase):
中的super()
调用会调用A
中的方法和{{1}中的方法永远不会被调用。当基类对于所有类都是通用的时,它会转到方法解析顺序的末尾,并且您可以确定无论如何定义类,基类方法都将是最后一个被调用的方法。
答案 1 :(得分:14)
感谢所有为此主题做出贡献的人。
The (currently) accepted answer不准确。正确的描述应该是:super()不仅适用于解析单继承,还有多重继承。其原因在@blckknght的评论中得到了很好的解释:
虽然显式调用基类方法可以用于非常简单的场景,例如提问者的示例,但如果基类本身从公共基础继承并且您不希望最终基类的方法被调用两次,它将会分解。这被称为“钻石继承”,对于许多多继承系统来说这是一个大问题(比如在C ++中)。 Python的协作多重继承(使用super())可以让你在很多情况下轻松解决它(虽然这并不是说合作的多继承层次结构很容易设计或总是一个好主意)。
正如@duncan pointed out一样,正确的方法是使用super(),但要始终如一地使用它。
super
确实适用于这种情况,但只有在您持续使用它时才有效。如果基类也没有全部使用super
它将无法工作,除非方法在object
中,否则你必须使用类似公共基类的东西来终止{{1}的链调用。
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
这个看似奇怪的顺序实际的通话顺序仍然是B.foo()
A.foo()
C.foo()
,它基于MRO。换句话说,
引用和修改
C, A, B
将在“first”“next”超类上调用foo方法。这基于类super()
的方法解析顺序(__mro__
)。
C
根据经验,如果您想要返回所有父方法但不关心调用顺序,请谨慎使用>>> C.__mro__
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>)
>>>
。否则,您可以选择以特定顺序显式调用父方法。
不要混用super()和显式调用的用法。否则,您将最终在this answer中提到令人讨厌的重复。
简而言之,在整个班级中始终如一地使用super()
将确保祖先的所有同名方法被调用一次,大约为MRO。如果方法恰好是super(...)
,call-only-the-first-candidate,那么这种调用ALL-ancestors(而不是see example in this blog post)行为可能在概念上更容易接受。
尽管如此,说“遵循MRO命令”可能并不十分精确。它实际上始终遵循“孙子”的MRO,不知何故。看到它的实际效果令人着迷。以下程序的结果可能与您的想法不完全相同。请注意__init__()
在2个不同的调用堆栈中保持相同的方式,A.__mro__
或super(A, self).name
在super(A, self).foo()
和A().foo()
触发时的行为方式不同。查看最后引用的结果。
C().foo()
Python 2.7.12的结果是:
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
答案 2 :(得分:8)
super()
只会解析给定方法的单个类类型,因此如果您从多个类继承并想要在两个类中调用该方法,则需要明确地执行此操作。 即 A.foo(self)
答案 3 :(得分:8)
Super将在“第一个”超类上调用foo
方法。这基于类__mro__
的方法解析顺序(C
)。
>>> C.__mro__
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>)
>>>
因此,如果您致电super(C, self).foo()
,则会调用A.foo
。如果将继承顺序更改为class C(B, A):
,那么这是相反的。 __mro__
现在看起来像:
>>> C.__mro__
(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>)
>>>
如果您在进行此更改后致电super(C, self).foo()
,则会调用B.foo()
。
答案 4 :(得分:5)
如果添加以下内容:
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()
然后super(C,self).foo()引用A.foo
输出
A.foo()
C.foo()
A.foo()
B.foo()
[编辑:包含其他信息和链接]
答案 5 :(得分:2)
正如Duncan所说,你可以得到可预测的结果,特别是如果你一直使用super()。
以下测试的结果对我有帮助:
class FooBase(object):
def foo(self):
print 'FooBase.foo()'
class A(FooBase):
def foo(self):
print 'A.foo() before super()'
super(A, self).foo()
print 'A.foo() after super()'
class B(FooBase):
def foo(self):
print 'B.foo() before super()'
super(B, self).foo()
print 'B.foo() after super()'
class C(A, B):
def foo(self):
print 'C.foo() before super()'
super(C, self).foo()
print 'C.foo() after super()'
这将打印出来:
>>> c = C()
>>> c.foo()
C.foo() before super()
A.foo() before super()
B.foo() before super()
FooBase.foo()
B.foo() after super()
A.foo() after super()
C.foo() after super()
答案 6 :(得分:0)
这可以通过super
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()'
super(C, self).foo() # calls A.foo()
super(A, self).foo() # calls B.foo()
答案 7 :(得分:0)
$this->db->select('projectID');
$this->db->from('propertytype');
$this->db->distinct('projectID');
$rec=$this->db->get()->result();
$arr=array();
foreach ($rec as $r) {
$this->db->select('typeID,projectID,typeName,typeSize,dimensionWidth,dimensionHeight');
$this->db->from('propertytype');
$this->db->where('projectID',$r->projectID);
$rec=$this->db->get()->result();
$arr[]=$rec;
}
echo "<pre>";print_r($arr);exit();
C类::
A级
答案 8 :(得分:0)
在这里您可以看到如何调用具有相同方法的类:-
这里,在类 D(A,B,C) 的方法 'feat()' 中
super(D, self).feature2() ----> 会调用A类的方法(feature2)。
super(A, self).feature2() ----> 会调用B类的方法(feature2)。
super(B, self).feature2() ---->会调用C类的方法(feature2)。
class A:
def __init__(self):
print("in A Init")
def feature1(self):
print("Feature 1-A working")
def feature2(self):
print("Feature 2-A working")
class B:
def __init__(self):
print("in B Init")
def feature1(self):
print("Feature 1-B working")
def feature2(self):
print("Feature 2-B working")
class C:
def __init__(self):
print("in C Init")
def feature1(self):
print("Feature 1-C working")
def feature2(self):
print("Feature 2-C working")
class D(A,B,C):
def __init__(self):
super().__init__()
print("in D init")
def feat(self):
super(D, self).feature2()
super(A, self).feature2()
print('\n\n')
### B().feature2() is calling explicitly, but
### super(A, self).feature2() is not.
### Both will give same result in below,
### It will print True below
print(B().feature2() == super(A, self).feature2())
print('\n\n')
super(B, self).feature2()
print(D.__mro__)
a1 = D()
a1.feat()
结果是:-
in A Init
in D init
Feature 2-A working
Feature 2-B working
in B Init
Feature 2-B working
Feature 2-B working
True
Feature 2-C working
(<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class
'__main__.C'>, <class 'object'>)