python面向对象-继承
一. 继承的概念和实现
1. 概念和语法
class 类名(父类):
说明:
1. 被继承的类放在括号中,B继承了A,则B称为A的子类,A称为B的父类
2. 子类继承父类,默认继承父类所有的属性和方法
3. 在Python中,所有类默认继承object类,object类是顶级类或基类;其他子类叫做派生类。
4. 在python中,类支持多继承
2. 示例:
class A(object): def __init__(self): self.name = "A" def fn1(self): print("A类方法执行") class B(A): pass b = B() print(b.name) # A b.fn1() # A类方法执行
说明:B类继承了A, 就继承了A的所有属性和方法
二. 多继承
1. 语法:
class 子类(父类1, 父类2,...): 代码
2. 子类重写父类同名方法和属性
子类使用属性和方法时,首先使用自己的属性和方法,自己没有时,才会去父类中找。
class A(object): def __init__(self): self.name = "A" def fn1(self): print("A类方法执行") class B(): def __init__(self): self.name = "B" def fn1(self): print("B类的方法") class C(A, B): def __init__(self): self.name = "C" def fn1(self): print("C的方法执行") cc = C() print(cc.name) # C cc.fn1() # C的方法执行
三. 多个父类存在同名方法属性时
当多个父类存在同名的属性或方法时,默认按定义的顺序,使用第一个父类的属性方法
class A(object): def __init__(self): self.name = "A" def fn1(self): print("A类方法执行") class B(): def __init__(self): self.name = "B" def fn1(self): print("B类的方法") class C(A, B): pass cc = C() print(cc.name) # A cc.fn1() # A类方法执行
四. 子类调用父类的属性和方法
语法:
父类类名.父类方法(self,其他参数)
class A(object): def __init__(self): self.name = "A" def fn1(self): print(f"{self.name}类方法执行") class B(): def __init__(self): self.name = "B" def fn2(self): print(f"{self.name}类的方法") class C(A, B): def __init__(self): self.name = "C" def fn1(self): A.__init__(self) #调用父类初始化方法,self显式传递 A.fn1(self) # 调用父类方法 self.__init__() # 这行如果没有,下面打印中name熟悉值为A print(f"{self.name}的方法执行") cc = C() cc.fn1() # C的方法执行
说明:
1. 通过类名调用方法时,self(当前对象)需要显式传递
2. 对象调用方法时,self不需要显式传递,如上面的 self.__init__() ,这个调用相当于对象直接调用
3. 通过self.属性 定义的属性与对象绑定,多次赋值时,后面的赋值覆盖前面的赋值,如上面的例子,父类和子类都有name属性,调用父类的 A.__init__(self) 会重新给name属性赋值,即不管是在子类中还是父类中,self.name操作的是同一个变量name
5. 多层继承
多层继承是指:子类继承父类后,子类也能被其他类继承
class A(object): def __init__(self): self.name = "A" self.a_name = "a_name" def fn1(self): print("a类fn1方法执行") def fn2(self): print("a类fn2方法执行") class B(A): def __init__(self): self.name = "B" self.b_name = "b_name" def fn1(self): print("b类fn1的方法") class C(B): def __init__(self): self.name = "C" cc = C() cc.fn1() # b类fn1的方法 cc.fn2() # a类fn2方法执行
说明:
1.上面代码有多层继承,C继承B, B继承A
2. 多层继承时,方法或属性的调用会由子类到父类,一层一层往上找。即如果当前类中有,则调用当前类的属性方法,否则去父类中找,没找到则继续往上找,知道找到为止
6. super() 调用父类方法
语法:
super(当前类名, self).父类方法()
super() 中的当前类名,和self 参数可以省略:
super(当前类名, self).父类方法()
class A(object): def __init__(self): self.name = "A" self.a_name = "a_name" def fn1(self): print("a类fn1方法执行") def fn2(self): print("a类fn2方法执行") class B(A): def __init__(self): self.name = "B" self.b_name = "b_name" def fn1(self): print(f"b类fn1的方法, name = {self.name}") class C(B): def __init__(self): self.name = "C" def fn3(self): super(C, self).fn1() # b类fn1的方法, name = C super().fn1() # b类fn1的方法, name = C cc = C() cc.fn3()
说明:
super()用于调用当前类的父类的方法,self可省略,省略时会自动传入
7. python中的方法解析顺序(Method Resolution Order,或MRO)
- MRO,就是方法解析顺序,是类的一个属性
- MRO在定义类时被计算出来,并保存在类的__mro__属性中。
- 在继承的情形中,MRO决定了方法(属性)搜索的顺序,最终决定调用哪个类的方法(属性)
对于支持继承的编程语言来说,其方法(属性)可能定义在当前类,也可能来自于基类,所以在方法调用时就需要对当前类和基类进行搜索以确定方法所在的位置。而搜索的顺序就是所谓的「方法解析顺序」(Method Resolution Order,或MRO)。对于只支持单继承的语言来说,MRO 一般比较简单;而对于 Python 这种支持多继承的语言来说,MRO 就复杂很多。
1. 查看类的MRO:
inspect.getmro(类名) 方法可以获取指定类的MRO。获取到的为一个元组,元组元素的顺序即为MRO顺序
import inspect class C(object): def dispatch(self): print("C中的dispatch") class D(object): pass class B(D): def dispatch(self): print("B中的dispatch") return super(B, self).dispatch() class A(B, C): pass print(inspect.getmro(A)) # (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class 'object'>) print(inspect.getmro(B)) # (<class '__main__.B'>, <class '__main__.D'>, <class 'object'>) print(inspect.getmro(C)) # (<class '__main__.C'>, <class 'object'>)
2. 计算MRO的方法
- MRO的计算顺序是根据类继承关系经过特殊算法计算得到,可以简单理解为采用从左至右的深度优先遍历,但是如果遍历中出现重复的类,只保留最后一个。如:
上面类结构可以表示为:
从A开始,按照深度优先遍历结果为A->B->D->object->C->object ,根据重复的类保留最后一个原则,最终顺序为A->B->D->C->object,这一结果和上面得到的结果一致。其他的类可通过相同方法获取到MRO
3. 方法调用举例
-
当使用 super(A, self).fn() 或 super().fn() 调用方法时,首先获取到self对象所对应的类的MRO, 找到这个MRO中当前类A所在的位置,从A的下一个节点开始,按照MRO顺序依次搜索方法fn,搜索到的第一个fn方法,即为要调用的方法
import inspect class C(object): def dispatch(self): print("C中的dispatch") class D(object): pass class B(D): def dispatch(self): print("B中的dispatch") return super(B, self).dispatch() class A(B, C): pass print(inspect.getmro(A)) # A->B->D->C->object a = A() a.dispatch()
输出结果:
C:\Users\11265\AppData\Local\Programs\Python\Python39\python.exe C:/Users/11265/Desktop/code/venv/demo.py (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class 'object'>) B中的dispatch C中的dispatch
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构