导读:今天首席CTO笔记来给各位分享关于Python继承可以继承多少次的相关内容,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!
本文目录一览:
1、Python中的多继承2、python的多重继承问题3、又来求助了,大神求解答 python类继承的问题4、Python类的多重继承问题深入分析5、Python中多继承的理解?6、Python可以多继承吗Python中的多继承
单继承:一个派生类的基类只有一个
多继承:一个派生类的基类有多个
一句话区分就是:单继承是一个生一个,多继承是多个生一个
多继承的基本语法:
子类定义构造方法时,需要将父类的构造方法调用一次。
案例演示:
在多继承中,所有基类的方法可以直接继承,但是属性需要手工初始化。如果派生类中没有 __init__ 方法,则默认获得第一个类的属性。如果派生类中有 __init__ 方法,则所有基类的属性都不会获得,需要手动逐一初始化。
我们定义一个ChineseStudent类,其继承关系如下:
调用基类的属性和方法
在不同的基类中存在相同的方法,派生类对象调用方法时会调用哪个父类的方法呢?
默认情况下,如果多个基类中有相同的方法,越在前面,优先级越高。
为了避免后期没必要的错误,建议基类之间存在重名的属性和方法应该尽量避免。
MRO(Method Resolution Order)方法解析顺序
如果是经典类(旧式类),MRO的方法--DFS(深度优先搜索)策略
如果是新式类,MRO的方法--BFS(广度优先搜索)策略
python的多重继承问题
楼上的回答的很正确,简单来说:在对类D进行实例化的时候,你依次对类C和类A进行了初始化,结果就会以后初始化的B为准了
实际上在子类里并不需要去初始化父类,你在实例化子类的同时,继承自父类的对象都会被创建
class A(object):
def __init__(self):
self.a = 1
class B(A):
def __init__(self):
self.a = 2
self.b = 2
class C(B,A):
pass
c = C()
c.a
2
另外补充一下。父类为新式类的情况下,继承顺序是有影响的。继承顺序上,经典类是深度优先,新式类是广度优先,两种混用的话,分分钟就晕乎了。可以去多做做实验,好好了解。
又来求助了,大神求解答 python类继承的问题
猜想你是想问多继承的属性搜索规则
Python的类是多重继承的。
Python2中:
Python的类又分经典类和新式类(显式继承object),分别对应深度优先和广度优先规则
python3中:
默认都是新式类,一般都是广度优先搜索
Python类的多重继承问题深入分析
Python类的多重继承问题深入分析
首先得说明的是,Python的类分为经典类 和 新式类
经典类是python2.2之前的东西,但是在2.7还在兼容,但是在3之后的版本就只承认新式类了
新式类在python2.2之后的版本中都可以使用
经典类和新式类的区别在于:
经典类是默认没有派生自某个基类的,而新式类是默认派生自object这个基类的:
代码如下:
# old style
class A():pass
# new style
class A(obejct):pass
2.经典类在类多重继承的时候是采用从左到右深度优先原则匹配方法的..而新式类是采用C3算法(不同于广度优先)进行匹配的
3.经典类是没有__MRO__和instance.mro()调用的,而新式类是有的.
为什么不用经典类,要更换到新式类
因为在经典类中的多重继承会有些问题...可能导致在继承树中的方法查询绕过后面的父类:
代码如下:
class A():
def foo1(self):
print "A"
class B(A):
def foo2(self):
pass
class C(A):
def foo1(self):
print "C"
class D(B, C):
pass
d = D()
d.foo1()
按照经典类的查找顺序从左到右深度优先的规则,在访问d.foo1()的时候,D这个类是没有的..那么往上查找,先找到B,里面没有,深度优先,访问A,找到了foo1(),所以这时候调用的是A的foo1(),从而导致C重写的foo1()被绕过.
所以python引入了新式类的概念,每个基类都继承自object并且,他的匹配规则也从深度优先换到了C3
C3算法
C3算法是怎么做匹配的呢..在问答版块上面讨论之后,归结如下:
C3算法的一个核心是merge.
在merge列表中,如果第一个序列mro的第一个类是出现在其它序列,并且也是第一个,或者不出现其它序列,那么这个类就会从这些序列中删除,并合到访问顺序列表中
比如:(引用问题中zhuangzebo的回答@zhuangzebo)
代码如下:
class A(O):pass
class B(O):pass
class C(O):pass
class D(A,B):pass
class E(C,D):pass
首先需要知道 O(object)的mro(method resolution order)列表是[O,]
那么接下来是:
代码如下:
mro(A) = [A, O]
mro(B) = [B, O]
mro(C) = [C, O]
mro(D) = [D] + merge(mro(A), mro(B), [A, B])
= [D] + merge([A, O], [B, O], [A, B])
= [D, A] + merge([O], [B, O], [B])
= [D, A, B] + merge([O], [O])
= [D, A, B, O]
mro(E) = [E] + merge(mro(C), mro(D), [C, D])
= [E] + merge([C, O], [D, A, B, O], [C, D])
= [E, C] + merge([O], [D, A, B, O], [D])
= [E, C, D] + merge([O], [A, B, O])
= [E, C, D, A, B] + merge([O], [O])
= [E, C, D, A, B, O]
然后还有一种特殊情况:
比如:
merge(DO,CO,C) 先merge的是D
merge(DO,CO,C) 先merge的是C
意思就是.当出现有 一个类出现在两个序列的头(比如C) 这种情况和 这个类只有在一个序列的头(比如D) 这种情况同时出现的时候,按照顺序方式匹配。
新式类生成的访问序列被存储在一个叫MRO的只读列表中..
你可以使用instance.__MRO__或者instance.mro()来访问
最后匹配的时候就按照MRO序列的顺序去匹配了
C3和广度优先的区别:
举个例子就完全明白了:
代码如下:
class A(object):pass
class B(A):pass
class C(B):pass
class D(A):pass
class E(D):pass
class F(C, E):pass
按照广度优先遍历,F的MRO序列应该是[F,C,E,B,D,A]
但是C3是[F,E,D,C,B,A]
意思是你可以当做C3是在一条链路上深度遍历到和另外一条链路的交叉点,然后去深度遍历另外一条链路,最后遍历交叉点
新式类和经典类的super和按类名访问问题
在经典类中,你如果要访问父类的话,是用类名来访问的..
代码如下:
class A():
def __init__(self):
print "A"
class B(A):
def __init__(self):
print "B"
A.__init__(self) #python不会默认调用父类的初始化函数的
这样子看起来没三问题,但是如果类的继承结构比较复杂,会导致代码的可维护性很差..
所以新式类推出了super这个东西...
代码如下:
class A():
def __init__(self):
print "A"
class B(A):
def __init__(self):
print "B"
super(B,self).__init__()
这时候,又有一个问题:当类是多重继承的时候,super访问的是哪一个类呢?
super实际上是通过__MRO__序列来确定访问哪一个类的...实际上就是调用__MRO__中此类后面的一个类的方法.
比如序列为[F,E,D,C,B,A]那么F中的super就是E,E的就是D
super和按照类名访问 混合使用带来的坑
代码如下:
class A(object):
def __init__(self):
print "enter A"
print "leave A"
class B(object):
def __init__(self):
print "enter B"
print "leave B"
class C(A):
def __init__(self):
print "enter C"
super(C, self).__init__()
print "leave C"
class D(A):
def __init__(self):
print "enter D"
super(D, self).__init__()
print "leave D"
class E(B, C):
def __init__(self):
print "enter E"
B.__init__(self)
C.__init__(self)
print "leave E"
class F(E, D):
def __init__(self):
print "enter F"
E.__init__(self)
D.__init__(self)
print "leave F"
这时候打印出来是:
代码如下:
enter F
enter E
enter B
leave B
enter C
enter D
enter A
leave A
leave D
leave C
leave E
enter D
enter A
leave A
leave D
leave F
可以看出来D和A的初始化函数被乱入了两次!
按类名访问就相当于C语言之前的GOTO语句...乱跳,然后再用super按顺序访问..就有问题了
所以建议就是要么一直用super,要么一直用按照类名访问
最佳实现:
避免多重继承
super使用一致
不要混用经典类和新式类
调用父类的时候注意检查类层次
以上便是本人对于python类的继承的认识了,希望对大家能有所帮助
Python中多继承的理解?
9.5.1. 多继承
Python 同样有限的支持多继承形式。多继承的类定义形如下例:
class DerivedClassName(Base1, Base2, Base3):
在大多数情况下,在最简单的情况下,你能想到的搜索属性从父类继承的深度优先,左到右,而不是搜索两次在同一个类层次结构中,其中有一个重叠。因此,如果在 DerivedClassName (示例中的派生类)中没有找到某个属性,就会搜索 Base1,然后(递归的)搜索其基类,如果最终没有找到,就搜索 Base2,以此类推。
实际上,super() 可以动态的改变解析顺序。这个方式可见于其它的一些多继承语言,类似 call-next-method,比单继承语言中的 super 更强大 。
动态调整顺序十分必要的,因为所有的多继承会有一到多个菱形关系(指有至少一个祖先类可以从子类经由多个继承路径到达)。例如,所有的 new-style 类继承自 object ,所以任意的多继承总是会有多于一条继承路径到达 object 。
为了防止重复访问基类,通过动态的线性化算法,每个类都按从左到右的顺序特别指定了顺序,每个祖先类只调用一次,这是单调的(意味着一个类被继承时不会影响它祖先的次序)。总算可以通过这种方式使得设计一个可靠并且可扩展的多继承类成为可能。进一步的内容请参见 .
Python可以多继承吗
Python支持多继承,与C++一样都会出现一种问题:子类继承的多个父类又继承了同一个父类,这时就有可能会出现父类构造方法被调用多次的情况。关于这个问题,我找了一些资料,虽然没有亲自全部验证,这里我总结一下自己对这个问题的看法。
Python和C++的关于这个问题的解决方案不太一样,当然Python还要看它的版本。
C++用的方案是引入了虚继承的语法避免同一个类被构造了多次。
Python用的方法是MRO(method resolution order,方法解析顺序) 。在在Python2.3之前,MRO的实现是基于DFS的,而在Python2.3以后MRO的实现是基于C3算法。找到的资料解释了一下更换算法的原因:
为什么采用C3算法
C3算法最早被提出是用于Lisp的,应用在Python中是为了解决原来基于深度优先搜索算法不满足本地优先级,和单调性的问题。
本地优先级:指声明时父类的顺序,比如C(A,B),如果访问C类对象属性时,应该根据声明顺序,优先查找A类,然后再查找B类。
单调性:如果在C的解析顺序中,A排在B的前面,那么在C的所有子类里,也必须满足这个顺序。
------------------------------新式类和旧式类中查找属性的顺序不同-------------------------------------
在新式类中,查找一个要调用的函数或者属性的时候,是广度优先搜搜的。
在旧式类当中,是深度优先搜索的。
结语:以上就是首席CTO笔记为大家介绍的关于Python继承可以继承多少次的全部内容了,希望对大家有所帮助,如果你还想了解更多这方面的信息,记得收藏关注本站。