导航:首页 > 编程语言 > python中同名方法继承

python中同名方法继承

发布时间:2024-05-23 05:52:40

‘壹’ python中类继承问题

Python新式类采用MRO算法处理继承关系,当调用c.say()方法时首先查找C类中是否定义了say()方法,若没有继续查找B类中是否定义了say()方法,找到B类中定义有say()方法,因此使用B类的say()方法。

‘贰’ Python中继承的理解与运用

9.5. 继承
当然,如果一种语言不支持继承就,“类”就没有什么意义。派生类的定义如下所示:
class DerivedClassName(BaseClassName):

命名 BaseClassName (示例中的基类名)必须与派生类定义在一个作用域内。除了类,还可以用表达式,基类定义在另一个模块中时这一点非常有用:
class DerivedClassName(modname.BaseClassName):
派生类定义的执行过程和基类是一样的。构造派生类对象时,就记住了基类。这在解析属性引用的时候尤其有用:如果在类中找不到请求调用的属性,就搜索基类。如果基类是由别的类派生而来,这个规则会递归的应用上去。
派生类的实例化没有什么特殊之处: DerivedClassName() (示列中的派生类)创建一个新的类实例。方法引用按如下规则解析:搜索对应的类属性,必要时沿基类链逐级搜索,如果找到了函数对象这个方法引用就是合法的。
派生类可能会覆盖其基类的方法。因为方法调用同一个对象中的其它方法时没有特权,基类的方法调用同一个基类的方法时,可能实际上最终调用了派生类中的覆盖方法。(对于 C++ 程序员来说,Python 中的所有方法本质上都是 虚 方法。)
派生类中的覆盖方法可能是想要扩充而不是简单的替代基类中的重名方法。有一个简单的方法可以直接调用基类方法,只要调用: BaseClassName.methodname(self, arguments)。有时这对于客户也很有用。(要注意只有 BaseClassName 在同一全局作用域定义或导入时才能这样用。)
Python 有两个用于继承的函数:
函数 isinstance() 用于检查实例类型: isinstance(obj, int) 只有在 obj.__class__ 是 int 或其它从 int 继承的类型
函数 issubclass() 用于检查类继承: issubclass(bool, int) 为 True,因为 bool 是 int 的子类。
然而, issubclass(float, int) 为 False,因为 float 不是 int 的子类。

‘叁’ Python中的面向对象(高级)之私有方法、多继承、多态

特征:私有属性与私有方法不能从外部被调用,也不能被子类继承

唯一写法:在属性或方法前面加上__(两个下划线)

我们写一个简单的例子,创建一个类,包含私有方法、私有属性、普通方法、普通属性,并生成一个实例

私有属性和私有方法可以从内部被调用(总不能我写了,但是哪都不让用吧)

我们试试在类里再加入一个新的方法,调用私有方法和属性

可以看到,私有属性和私有方法是可以在类内部被调用的。

举个私有属性应用场景的例子


二。object类

我们试一下


三。多继承

一个子类可以继承多个父类,用逗号隔开

多个父类中有同名方法时,按照继承顺序进行调用


四。多态

当不同的实例,有同名的方法时,我们可以一个函数,传入不同的实例,执行对应的方法。

我们定义一个猫和一个狗的类,两个类中都有'叫'的方法。并各生成一个实例。

定义一个函数,用函数来调用'叫'的方法

这就叫多态。

‘肆’ Python类的继承与多态详细介绍

类(Class): 用来描述具有相同的属性和方法的对象的集合。

类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。

类有一个名为 __init__() 的特殊方法(构造方法),该方法在类实例化时会自动调用

self:self 代表的是类的实例,代表当前对象的地址,而 self.class 则指向类。

类调用 Car.weight

实例化 car01=Car(5)

实例对象调用 car01.weght

我们在构造类时,Python3默认我们继承了object这个基类,我个人理解object就是个空的类,可以不用管为何要在括号中写上object,这是Python3的特性,在python2中如果你没有写object的话不会默认继承了object这个基类。

同样的我们自己希望继承的父类只需要把objetc改为我们自己定义的类名即可。子类中可以拥有父类中所有的公有属性和方法,但是可以通过在变量名前加下划线使其变为私有,这样子类就不可以访问父类中的成员了。

以下三个公交车类的父类均为客车类,我们可以写一个funcs方法使得每次调用funcs方法时,传入不同的对象以执行不同的func方法,具体实现如下:

主函数

可以看到,我将小 汽车 实例化为带有重量为5t的一个具体对象,将客车实例化为带有重量为20t的一个具体对象,将三个公交车实例化为带有重量为15t的一个具体对象.

如上图所示,我每次在调用funcs方法时都传入了一个实例化对象,funcs根据不同的对象执行相应的内部方法。

‘伍’ 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中同名方法继承相关的资料

热点内容
php定时刷新页面 浏览:506
二层交换机怎么连接服务器 浏览:415
生命最后的八分钟源码 浏览:710
围棋需要什么app 浏览:894
10款本田crv压缩机不工作风扇会转 浏览:71
算法导论的数学基础 浏览:125
pdfazw 浏览:288
c的预处理命令 浏览:380
phpsecure 浏览:213
服务器内部出问题是什么意思 浏览:657
抖音解压视频神剧 浏览:259
html与java后台交互 浏览:588
算法色调分离 浏览:844
哪个公考app 浏览:130
雨燕13空调压缩机 浏览:41
python多维数组去重 浏览:511
火柴人游戏源码 浏览:810
青海一机xk713数控铣床编程 浏览:52
分子遗传学pdf 浏览:406
区块链加密猫游戏 浏览:340