6.1 继承 — 简单搞定
继承是面向对象编程 (OOP) 的一个基本概念,它允许一个类(称为子类或派生类)继承另一个类(称为父类或超类)的字段和方法。
这种方法可以创建更通用的类和重用代码,从而提高代码的组织性和可维护性。
为啥要用继承?
假设你需要写一些代码,你决定用类来实现。然后你发现你的项目中已经有一个类,几乎能完成你需要的工作。你可以简单地复制这个类的代码到自己的类中,然后开开心心地用。
或者你可以「像复制一样」。你可以将那个类声明为你类的父类,这样 Python 就会给你的类加上父类的行为。
想象一下,你是大自然,想要创造一只狗。是用十亿年从细菌开始进化一只狗更快,还是用二十万年驯化一只狼更快?
基本继承的例子
假设你有一个父类 Animal
,它有一个字段 name:
class Animal:
def __init__(self, name):
self.name = name
我们想为它创建两个子类 — Dog
和 Cat
,并为它们都添加一个 speak
方法:
class Dog(Animal):
def speak(self):
return f"{self.name} says Woof!"
class Cat(Animal):
def speak(self):
return f"{self.name} says Meow!"
在上面的例子中,子类 Dog
和 Cat
从 Animal
中继承,并添加了 speak
方法。
类 Dog
:
- 从
Animal
继承属性name
。 - 添加了一个返回狗特定字符串的
speak
方法。
类 Cat
:
- 从
Animal
继承属性name
。 - 添加了一个返回猫特定字符串的
speak
方法。
最终的代码看起来是这样的:
class Animal:
def __init__(self, name):
self.name = name
class Dog(Animal):
def speak(self):
return f"{self.name} says Woof!"
class Cat(Animal):
def speak(self):
return f"{self.name} says Meow!"
dog = Dog("Buddy")
cat = Cat("Whiskers")
print(dog.speak()) # 输出:Buddy says Woof!
print(cat.speak()) # 输出:Whiskers says Meow!
在这个例子中,Animal
是父类,Dog
和 Cat
是子类。子类继承了父类 Animal
的属性 name
和方法 __init__
,但是增加了 speak
方法。
6.2 继承的内部机制
如果你给你的类加了个父类,这很像是你复制了父类的代码到你的类中。
class Animal:
def __init__(self, name):
self.name = name
class Dog(Animal):
def __init__(self, name):
super().__init__(name) # 调用父类构造函数
def speak(self):
return f"{self.name} says Woof!"
class Cat(Animal):
def __init__(self, name):
super().__init__(name) # 调用父类构造函数
def speak(self):
return f"{self.name} says Meow!"
dog = Dog("Buddy")
cat = Cat("Whiskers")
print(dog.speak()) # 输出:Buddy says Woof!
print(cat.speak()) # 输出:Whiskers says Meow!
这不是一个完全准确的描述,但如果你从未接触过继承的概念,你可以暂时这样理解。我们稍后会添加更多细节。
6.3 继承的层次结构
设计复杂模型的大型类群时,你常常会遇到完整的继承层次结构。
例如,你有一个 Animal
类——这是所有动物的基类:
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError("Subclass must implement abstract method")
我们甚至给它加了一个 speak
方法,但由于抽象的动物不说话,这个方法只是抛出一个 NotImplementedError
异常——这是标准做法。
然后我们添加中间类,代表动物的类别:Mammal
是哺乳动物,Bird
是鸟类。
class Mammal(Animal):
def __init__(self, name, fur_color):
super().__init__(name) # 调用父类构造函数
self.fur_color = fur_color
class Bird(Animal):
def __init__(self, name, wing_span):
super().__init__(name) # 调用父类构造函数
self.wing_span = wing_span
def fly(self):
return f"{self.name} is flying with a wingspan of {self.wing_span} meters."
最后,只有在最终阶段才出现特定动物种类的类:
class Dog(Mammal):
def speak(self):
return f"{self.name} says Woof!"
class Cat(Mammal):
def speak(self):
return f"{self.name} says Meow!"
class Parrot(Bird):
def speak(self):
return f"{self.name} says Squawk!"
最终的代码如下:
animals = [Dog("Buddy", "brown"), Cat("Whiskers", "white"), Parrot("Polly", 0.5)]
for animal in animals:
print(animal.speak())
print(f"{dog.name} has {dog.fur_color} fur.") # 输出:Buddy has brown fur.
print(f"{cat.name} has {cat.fur_color} fur.") # 输出:Whiskers has white fur.
print(parrot.fly()) # 输出:Polly is flying with a wingspan of 0.5 meters.
虽然技术上没有禁止创建有数十个祖先的继承层次结构,但重要的是要记住,在没有必要的情况下,最好保持简单。简单就是力量。
GO TO FULL VERSION