当前位置: 首页 > 面试题库 >

Python和多重继承中的方法顺序

暨高洁
2023-03-14
问题内容

在Python中,如果您使用相同的方法定义两个类,并希望这两个类成为父类,则如下所示:

class A(object):
     def hello(self):
         print "hello from class a"

和:

class B(object):
     def hello(self):
         print "hello from class b"

当您定义子类并以A和B的顺序html" target="_blank">添加两个父类时:

class C(A, B):
     def __init__(self):
         self.hello()

调用self.method()时使用的方法是属于A的方法,即继承列表中的第一个类:

>>> C()
hello from class a
<__main__.C object at 0x10571e9d0>

尽管在我所有的测试用例中似乎都是如此,但我无法在文档或在线中找到在任何平台和该语言实现中都可以安全使用的地方。任何人都可以肯定地说,假设列表中的第一个继承的类将始终是其他类所使用的方法(无论super().
init
()调用如何),还是可以将我指向确认这一事实的官方文档呢?

谢谢,


问题答案:

是的,可以保证,如介绍新算法以计算方法分辨率顺序(即C3线性化)的文档中所述。

不使用此算法的mro实现并不真正符合python语言(2.3版以上)。AFAIK当前所有实现 使用C3线性化。

C3线性化满足局部优先级排序和单调性。本地优先级排序意味着一类C(B1, ..., Bn)将在mro基类Bi中具有在继承列表中列出的顺序。

一个例子也许可以更好地解释单调性:

>>> class A(object): pass
>>> class B(object): pass
>>> class C(object): pass
>>> class D(object): pass
>>> class E(object): pass
>>> class K1(A,B,C): pass
>>> class K2(D,B,E): pass
>>> class K3(D,A):   pass
>>> class Z(K1,K2,K3): pass

python2.2的旧mro( 不是 单调的),这些是上述类的线性化:

L[A] = A O
L[B] = B O
L[C] = C O
L[D] = D O
L[E] = E O
L[K1]= K1 A B C O
L[K2]= K2 D B E O
L[K3]= K3 D A O
L[Z] = Z K1 K3 A K2 D B C E O
# in current versions of python (2.3+):
# L[Z] = Z K1 K2 K3 D A B C E O

在这里,您可以看到,在的线性化中Z,类位于A之前D,而在其线性化中K3则位于 之后
D。单调性是线性化的属性,因此在继承时不存在此类交换。如果某个类XY其父级的所有线性化中均在类之前,则Y在最终线性化中它也将在类之前。

现在,如果我们考虑一堂课C(B1, ..., Bn)。按照局部优先顺序,这些类B1, ..., Bn将在的线性化中按该顺序找到C。通过单调性,我们无法BiBi自身之前找到s的子类。由此可见,的线性化(C如果存在)必须以C和开头B1

请注意,在某些情况下,您 无法 计算线性化,而python会抱怨,例如:

>>> class A(object):pass
... 
>>> class B(object, A): pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Cannot create a consistent method resolution
order (MRO) for bases object, A

但是,如果交换类,则可以线性化层次结构:

>>> class B(A, object): pass
... 
>>> B.mro()
[<class '__main__.B'>, <class '__main__.A'>, <class 'object'>]

如果父类没有共同的基数(object显然不是其他基数),那么显然的线性化C(B1, ..., Bn)将以B1(除外object)的线性化开始,然后将遵循B2etc的线性化,并将以:的线性化结束Bn

>>> class A(object): pass
... 
>>> class B(object): pass
... 
>>> class A1(A): pass
... 
>>> class A2(A1): pass
... 
>>> class B1(B): pass
... 
>>> class C(object): pass
... 
>>> class C1(C): pass
... 
>>> class C2(C1):pass
... 
>>> class C3(C2): pass
... 
>>> class D(A2, B1, C3): pass
... 
>>> D.mro()
[<class '__main__.D'>, <class '__main__.A2'>, <class '__main__.A1'>, <class '__main__.A'>, <class '__main__.B1'>, <class '__main__.B'>, <class '__main__.C3'>, <class '__main__.C2'>, <class '__main__.C1'>, <class '__main__.C'>, <class 'object'>]

Bis之间有一些通用子类时,事情开始变得怪异,在这种情况下python找到了您期望的不违反局部优先顺序和单调性的顺序,否则将引发错误。



 类似资料:
  • 本文向大家介绍Python多重继承的方法解析执行顺序实例分析,包括了Python多重继承的方法解析执行顺序实例分析的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Python多重继承的方法解析执行顺序。分享给大家供大家参考,具体如下: 任何实现多重继承的语言都要处理潜在的命名冲突, 这种冲突由不相关的祖先类实现同名方法引起 这里B和C都实现了eat方法, 在 D 的实例上调用 d.eat(

  • 在面向对象的程序设计中,定义一个新的 class 的时候,可以从某个现有的 class 继承,新的 class 称为子类,而被继承的 class 称为基类、父类或超类。 Python 中继承的语法如下: class Parent: pass class Child(Parent): pass 在第 1 行,定义了父类 Parent; 在第 4 行,定义了子类 Child,语法

  • 问题内容: 这是我遇到的一个测试练习问题,希望您能帮助我理解概念 让Hawk成为Bird的子类。假设某个类有两个重载的方法void foo(Hawk h)和void foo(Bird b)。在声明Bird x = new Hawk()之后,将在调用foo(x)中执行哪个版本; 这是我到目前为止的代码,有人可以向我解释为什么foo(bird b)被执行吗? 问题答案: Java执行重载解析以选择方法

  • 问题内容: 我有两个课,和。它们看起来像这样: 此错误指向Field的: 我希望首先调用Background init ()。要将“ a,b”传递给Fields的 init (),Field会分配a和b,然后将其中包含三个0的列表分配给field。然后让Background的 init ()继续,然后调用它自己的buildField()并用包含c的列表覆盖self.field。 似乎我还没有完全理

  • 主要内容:多继承下的构造函数,命名冲突在前面的例子中,派生类都只有一个基类,称为 单继承(Single Inheritance)。除此之外, C++也支持 多继承(Multiple Inheritance),即一个派生类可以有两个或多个基类。 多继承容易让代码逻辑复杂、思路混乱,一直备受争议,中小型项目中较少使用,后来的 Java、 C#、 PHP 等干脆取消了多继承。 多继承的语法也很简单,将多个基类用逗号隔开即可。例如已声明了类A

  • 本文向大家介绍Java和多重继承,包括了Java和多重继承的使用技巧和注意事项,需要的朋友参考一下 Java不支持多重继承。这意味着一个类不能扩展一个以上的类。因此,跟随是非法的 但是,一个类可以实现一个或多个接口,这帮助Java摆脱了多重继承的可能性。extend关键字仅使用一次,并且父接口在逗号分隔的列表中声明。例如,如果Hockey接口同时扩展了Sports和Event,它将被声明为- 下面