Python_面向对象:继承
一、继承概念
二、继承特点
继承的特点:
- 子类对象可以直接访问父类中未私有化的属性和方法
- 子类对象不可以直接调用父类中私有属性和私有方法
- 父类对象不能访问子类特有的属性和方法
- 继承具有传递性
继承的优缺点:
- 优点:可以简化代码,减少冗余;可提高代码的可维护性;提高代码的安全性;是多态的前提
- 缺点:在继承关系中,耦合性是比较高的【如果修改父类,子类也随之发生改变】
解释:耦合性和内聚性被用来描述类与类之间的关系,耦合性越低,内聚性越高,说明代码越好
# 定义父类 class Person: def __init__(self, name): self.name = name self.__age = 18 def eat(self): print(F"{self.name}要吃饭") def __drink(self): print(F"{self.name}要喝水") # 定义子类 class Police(Person): def maintain_peace(self): print(F"{self.name}能维护治安") # 定义子类 class SpecialPolice(Police): def counter_terrorism(self): print(F"{self.name}能反恐") # 创建父类对象 xiaohong = Person("小红") # 创建子类对象 xiaojiang = Police("小江") xiaoming = SpecialPolice("小明") # 1.子类对象可以直接访问父类中未私有化的属性和方法 print(xiaojiang.name) xiaojiang.eat() # 2.子类对象不可以直接调用父类中私有化的属性和方法 # xiaojiang.__drink() # AttributeError: 'Police' object has no attribute '__drink' # 3.父类对象无法访问子类中特有的属性和方法 # xiaohong.maintain_peace() # 报错 AttributeError: 'Person' object has no attribute 'maintain_peace' # 4.继承具有传递性 xiaoming.eat() # 能访问Police类继承的方法
三、单继承&多继承
继承分为单继承和多继承。
单继承:一个子类只有一个父类,子类具有父类所有属性和方法。
多继承:一个子类有多个父类,子类具有多个父类的属性和方法。
3.1 单继承
3.1.1 语法
父类:
class 父类类名(object):
类体【子类公共部分】
子类:
class 子类类名(父类类名):
类体【子类特有的部分】
注意:object是所有类的父类
3.1.2 代码演示
# 定义父类 class Person: def __init__(self, name): self.name = name def eat(self): print(F"{self.name}要吃饭") def drink(self): print(F"{self.name}要喝水") # 定义子类 class Police(Person): def maintain_peace(self): print(F"{self.name}是警察,能维护治安") # 创建父类对象 xiaohong = Person("小红") xiaohong.eat() xiaohong.drink() # 创建子类对象 xiaoming = Police("小明") xiaoming.eat() xiaoming.drink() xiaoming.maintain_peace()
3.2 多继承
3.2.1 语法
父类:
class 父类类名1(object):
类体【子类公共部分】
父类:
class 父类类名2(object):
类体【子类公共部分】
子类:
class 子类类名(父类类名1, 父类类名2):
类体【子类特有的部分】
3.2.2 代码演示
# 定义父类1 class Person: def __init__(self, name): self.name = name def eat(self): print(F"{self.name}要吃饭") def drink(self): print(F"{self.name}要喝水") # 定义父类2 class Police: def __init__(self, name): self.name = name def maintain_peace(self): print(F"{self.name}能维护和平") # 定义子类 class SpecialPolice(Person, Police): def counter_terrorism(self): print(F"{self.name}能反恐") # 创建子类对象 xiaojiang = SpecialPolice("小江") xiaojiang.eat() xiaojiang.drink() xiaojiang.maintain_peace() xiaojiang.counter_terrorism()
3.2.3 mro多继承的调用顺序
多继承时,父类之间应尽量避免使用重名的方法或属性;反之如果继续的父类存在同名的属性或方法,应该尽量避免使用多继承。
因为当存在相同的属性或方法时,会在调用该属性或方法时产生混淆的情况,即不清楚到底调用的哪个父类的属性或方法。
如果在不清楚父类存在同名属性或方法的情况下调用了这些属性或方法,那怎么知道调用的是哪个父类的呢?
那就需要使用 类名.__mro__ 查看python的方法解析顺序。(mro既是Method Resolution Order方法解析顺序)
class TestA: def test(self): print("A类的test方法") class TestB: def test(self): print("B类的test方法") class TestC(TestB, TestA): def demo(self): pass c = TestC() c.test() # B类的test方法 print(TestC.__mro__) # 输出:(class '__main__.TestC'>, <class '__main__.TestB'>, <class '__main__.TestA'>, <class 'object'>) # 说明:元组中的顺序就是调用类的顺序,比如c对象调用test方法,python会先去TestC中查找test,若没查找到则继续在TestB中查找, # 若在B中查找到了test方法,则直接执行该方法,不再在后续的类中查找test方法,利用该原理就可以达到方法重写的功能。
四、重写父类方法
当继承的父类的方法完全不能满足开发需求时,就需要对父类的方法完全重写。
实现重写的方法为在子类中构造一个相同名称的方法,当调用这个方法时,就会优先调用子类中的方法。实现该功能的原理是MRO即方法解析顺序。
class TestA: def test(self): print("A类的test方法") class TestB(TestA): def test(self): print("B类重写的test方法") b = TestB() b.test() # 输出:B类重写的test方法 print(TestB.__mro__) # (<class '__main__.TestB'>, <class '__main__.TestA'>, <class 'object'>)
五、修改父类方法
当继承的父类的方法不完全满足开发需求时,就需要在子类中重写部分需求,那么就需要在子类中调用父类中的方法,将父类现有的方法应用到子类中。
在子类中调用父类的方法有3种:
- 父类名.父类方法(self, *args, **kwargs)
- super().父类方法(*args, **kwargs)
- super(子类名, self).父类方法(*args, **kwargs)
上面3中方法在单继承中功能是一样的,在多继承中方法1能执行指定父类的方法,方法2和方法3是按 mro 的解析顺序执行。
class Bus(object): def __init__(self): print("公交车类初始化方法") def run(self): print("公交车这样跑") class Bike(object): def __init__(self): print("自行车类初始化方法") def run(self): print("自行车这样跑") class Car(Bus, Bike): def __init__(self, type): # 父类属性不够,在子类中新增属性 self.type = type # 继承父类方法的3种方式 # 1、父类名.父类方法(self, *args, **kwargs) Bike.__init__(self) # 2、super().父类方法(*args, **kwargs) super().__init__() # 3、super(子类名, self).父类方法(*args, **kwargs) super(Car, self).__init__() def run(self): # 修改父类方法 Bus.run(self) super().run() super(Car, self).run() c = Car("a") c.run()
执行结果
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ThreeJs-16智慧城市项目(重磅以及未来发展ai)
· .NET 原生驾驭 AI 新基建实战系列(一):向量数据库的应用与畅想
· 软件产品开发中常见的10个问题及处理方法
· Vite CVE-2025-30208 安全漏洞
· MQ 如何保证数据一致性?