继承是什么
继承描述的是两个类之间的关系:子类继承父类,就可以获取到父类中的属性和方法。
为什么要用它?看这个例子:燃油车和电车都需要"启动、停止、行驶",如果各写一遍就是重复代码。把公共部分抽出来做成 Car(父类),两种车继承它即可:
class Car:
def __init__(self, brand, model, color):
self.brand = brand
self.model = model
self.color = color
def start(self):
print(f'{self.brand} {self.model} 正在启动...')
def stop(self):
print(f'{self.brand} {self.model} 停止行驶...')
def run(self):
print(f'{self.brand} {self.model} 正在行驶...')
class FuelCar(Car): # 子类(父类):括号里写父类的类名
pass
class ElectricCar(Car):
passc1 = FuelCar("BMW", "X5", "黑色") # 子类不需要自己写 __init__,直接用父类的
c1.start() # BMW X5 正在启动...
c1.run() # BMW X5 正在行驶...IMPORTANT
子类会把父类**公共的(非私有)**属性和方法继承下来,私有的继承不到。所以父类里 self.__owner 这类私有属性,子类无法直接使用(可以先调父类的 get_owner() 取脱敏值)。
方法重写
重写是指子类继承父类后,如果父类中的方法不满足需求,可以在子类中重新定义一个同名方法,从而用子类的实现替换父类的实现。
class Car:
def charge(self):
print(f'{self.brand} {self.model} 正在补充燃料...')
class FuelCar(Car):
def charge(self):
Car.charge(self) # 方式二:父类名.方法名(self)
print(f'{self.brand} {self.model} 正在加油...')
class ElectricCar(Car):
def charge(self):
super().charge() # 方式一:super().方法名()
print(f'{self.brand} {self.model} 正在充电...')| 问题 | 答案 |
|---|---|
| 什么是重写? | 在子类中重新定义与父类同名的方法,用子类自己的实现替换父类的实现 |
| 如何在子类里调用父类的方法? | 方式一 super().方法名();方式二 父类名.方法名(self) |
多继承与 MRO
多继承指的是一个子类同时继承多个父类(会把多个父类中非私有的属性和方法都继承下来)。
class XiaomiAiDriving: # 智驾系统
def __init__(self, version="V1.0"):
self.version = version
def run(self):
print(f'使用智驾系统{self.version}正在行驶...')
class SmartCar(Car, XiaomiAiDriving): # 同时继承两个父类
def __init__(self, brand, model, color, version="V1.0"):
Car.__init__(self, brand, model, color)
XiaomiAiDriving.__init__(self, version)
def run(self):
Car.run(self) # 两个父类的 run 都想用,就都显式调用
XiaomiAiDriving.run(self)NOTE
MRO:Method Resolution Order(方法解析顺序)。当一个类继承了多个父类时,默认优先使用第一个父类中的同名属性或方法;查看顺序可以用 类名.__mro__ 属性或 类名.mro() 方法。
相关
练习题
一、知识回顾(读完直接做下面的实践题)
- 继承描述的是两个类之间的关系:子类继承父类,就能获取父类的属性和方法
- 继承的语法:
class 子类(父类): - 子类能继承父类只有非私有的属性和方法
- 重写是指在子类中重新定义与父类同名的方法,用子类的实现替换父类
- 在子类里调用父类方法有两种写法:
super().方法名()和父类名.方法名(self) - 多继承的语法:
class 子类(父类1, 父类2):;同名方法默认优先使用第一个父类的 - 查看方法解析顺序用
类名.__mro__属性或类名.mro()方法,缩写是 MRO(Method Resolution Order,方法解析顺序)
二、裸写题
- 提示(先自己想,实在想不出再点开)
一级 · 思路:公共的属性/方法放父类,子类只写
class 子类(父类): pass二级 · 方法:class Dog(Animal):三级 · 骨架:子类不用写__init__,直接用父类的- 参考答案(做完再点开)
python# 2-1 class Animal: def __init__(self, name): self.name = name def speak(self): print(f'{self.name} 发出声音...') class Dog(Animal): def speak(self): super().speak() # 2-2:先调父类实现 print(f'{self.name}: 汪汪!') class Cat(Animal): def speak(self): super().speak() print(f'{self.name}: 喵喵~') d = Dog("旺财") c = Cat("咪咪") d.speak() c.speak()- 提示(先自己想,实在想不出再点开)
一级 · 思路:写一个和父类同名的方法即可覆盖 二级 · 方法:
super().speak()三级 · 骨架:先super().speak()再打印子类特有的声音- 参考答案(做完再点开)
python# 2-2:重写 speak —— 先 super() 调父类实现,再写自己的实现 class Dog(Animal): def speak(self): super().speak() print(f'{self.name}: 汪汪!') class Cat(Animal): def speak(self): super().speak() print(f'{self.name}: 喵喵~') d = Dog("旺财") c = Cat("咪咪") d.speak() c.speak()- 提示(先自己想,实在想不出再点开)
一级 · 思路:多继承把两个父类的本事合到一个子类;用 MRO 确认同名方法用谁的 二级 · 方法:
class GuideDog(Dog, Trained):/GuideDog.__mro__三级 · 骨架:for c in GuideDog.__mro__: print(c.__name__)- 参考答案(做完再点开)
python# 2-3:多继承(Dog、Animal 见 2-1) class Trained: def guide(self): print("正在引导主人过马路...") class GuideDog(Dog, Trained): # 2-3:多继承 pass g = GuideDog("豆豆") g.speak() # 用 Dog 的 speak g.guide() # 用 Trained 的 guide for cls in GuideDog.__mro__: print(cls.__name__) # GuideDog → Dog → Animal → Trained → object
