Python继承让一个类(子类)自动获得另一个类(父类)已有的属性和方法,并可以在子类里追加字段,或重写同名方法以改变行为。公共逻辑放在父类,差异放在子类,能减少重复代码。
先看一次继承
括号里写上父类名,子类就挂到这条继承链上。下例中 Dog 重写了 speak,但仍然是 Animal 的一种,isinstance 会得到 True:
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
print(f"{self.name} 发出声音")
class Dog(Animal):
def speak(self):
print(f"{self.name} 汪汪!")
d = Dog("旺财")
d.speak()
print(isinstance(d, Animal))基本写法
语法是 class 子类(父类)。子类即使几乎是空的,也能使用父类里定义好的方法与在父类 __init__ 里设置的属性:
Dog、Cat 继承 Animal 后自动拥有父类的属性与方法(如 eat),子类可以重写方法改变行为。
class Animal:
def __init__(self, name):
self.name = name
def eat(self):
print(f"{self.name} 在吃东西")
class Cat(Animal):
pass
c = Cat("咪咪")
c.eat()
print(c.name)
super() 调用父类
子类若自己写了 __init__,默认不会自动执行父类的 __init__。需要父类那部分初始化时,用 super().__init__(...) 显式调用,再写子类自己的字段:
class Animal:
def __init__(self, name):
self.name = name
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name)
self.breed = breed
d = Dog("旺财", "金毛")
print(d.name, d.breed)方法重写
子类定义与父类同名的方法,就会覆盖父类实现。对一组不同子类对象调用同一方法名,各自走出自己的版本,这是多态常见的落地方式:
class Animal:
def speak(self):
print("...")
class Dog(Animal):
def speak(self):
print("汪汪!")
class Cat(Animal):
def speak(self):
print("喵喵!")
for a in [Dog(), Cat()]:
a.speak()
多层继承
子类还可以再被继承,形成一条链。最底层的实例能沿链向上找到祖先类的方法:
class A:
def fa(self):
print("A")
class B(A):
def fb(self):
print("B")
class C(B):
def fc(self):
print("C")
c = C()
c.fa()
c.fb()
c.fc()多重继承
一个类也可以同时列出多个父类,从而混入多组能力。同名方法冲突时,由方法解析顺序(MRO)决定用哪一个,括号里靠前的父类通常更优先。能力组合变复杂时,要谨慎使用:
class Swim:
def swim(self):
print("游泳")
class Run:
def run(self):
print("跑步")
class Duck(Swim, Run):
pass
d = Duck()
d.swim()
d.run()isinstance 与 issubclass
isinstance对象, 类型) 判断对象是否为该类型或其子类的实例。issubclass(子, 父) 判断两个类之间是否存在继承关系:
print(isinstance(d, Duck))
print(isinstance(d, Swim))
print(issubclass(Duck, Run))
print(issubclass(Duck, int))常见错误
- 子类写了
__init__却忘记super().__init__,父类里本该设置的属性就不存在。 - 继承层数堆得过深时,阅读成本上升,有时用组合(对象里持有另一个对象)更清楚。
- 多重继承下同名方法依赖 MRO,结果可能和直觉不一致,尽量保持父类职责干净。