一、继承的基本概念
1.1 什么是继承?
继承是面向对象编程的四大支柱之一(封装、继承、多态、抽象),允许一个类(子类)基于另一个类(父类)来创建,从而复用父类的属性和方法。
1.2 继承的主要目的
· 代码复用:避免重复编写相同的代码
· 扩展性:在现有类基础上添加新功能
· 层次化建模:建立类之间的层次关系
· 多态支持:为多态提供基础
二、继承的类型
2.1 单继承
一个子类只继承一个父类,这是最简单的继承形式。
```python
class Animal:
def init(self, name):
self.name = name
def eat(self):
return f"{self.name}正在吃东西"
class Dog(Animal): # 单继承
def bark(self):
return f"{self.name}在汪汪叫"
使用
dog = Dog("旺财")
print(dog.eat()) # 继承自Animal
print(dog.bark()) # Dog自己的方法
```
2.2 多继承
一个子类可以继承多个父类(Python支持,但Java不支持多继承)。
```python
class Flyable:
def fly(self):
return "我能飞"
class Swimmable:
def swim(self):
return "我能游泳"
class Duck(Flyable, Swimmable): # 多继承
def quack(self):
return "嘎嘎叫"
使用
duck = Duck()
print(duck.fly()) # 来自Flyable
print(duck.swim()) # 来自Swimmable
print(duck.quack()) # 自己的方法
```
2.3 多层继承
继承可以形成链式结构:A继承B,B继承C。
```python
class GrandParent:
def family_trait(self):
return "家族特征"
class Parent(GrandParent):
def parent_method(self):
return "父类方法"
class Child(Parent): # 间接继承GrandParent
def child_method(self):
return "子类方法"
使用
child = Child()
print(child.family_trait()) # 继承链:Child->Parent->GrandParent
```
2.4 层次继承
多个类继承同一个父类,形成层次结构。
```python
class Vehicle:
def init(self, brand):
self.brand = brand
def start(self):
return "车辆启动"
class Car(Vehicle):
def drive(self):
return f"{self.brand}汽车正在行驶"
class Bike(Vehicle):
def pedal(self):
return f"{self.brand}自行车正在骑行"
Car和Bike都是Vehicle的子类,形成层次结构
```
三、继承的关键机制
3.1 方法重写(Override)
子类可以重新定义父类的方法,实现自己的版本。
```python
class Animal:
def make_sound(self):
return "动物发出声音"
class Cat(Animal):
def make_sound(self): # 重写父类方法
return "喵喵"
class Dog(Animal):
def make_sound(self): # 重写父类方法
return "汪汪"
多态表现
animals = [Cat(), Dog()]
for animal in animals:
print(animal.make_sound()) # 分别输出"喵喵"和"汪汪"
```
3.2 方法扩展(Extend)
子类在父类方法的基础上添加新功能。
```python
class Logger:
def log(self, message):
print(f"日志: {message}")
class TimestampLogger(Logger):
def log(self, message):
调用父类方法并扩展
from datetime import datetime
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
super().log(f"[{timestamp}] {message}") # 使用super()调用父类方法
使用
logger = TimestampLogger()
logger.log("系统启动") # 输出: 日志: [2024-01-15 10:30:00] 系统启动
```
3.3 super()函数
super()用于调用父类的方法,有三种常见用途:
```python
class Parent:
def init(self, name):
self.name = name
def greet(self):
return f"你好,我是{self.name}"
class Child(Parent):
def init(self, name, age):
1. 调用父类的__init__
super().init(name)
self.age = age
def greet(self):
2. 扩展父类方法
parent_greeting = super().greet()
return f"{parent_greeting},今年{self.age}岁"
@classmethod
def create_baby(cls, name):
3. 调用父类的类方法(如果有)
return cls(name, 0)
使用
child = Child("小明", 10)
print(child.greet()) # 你好,我是小明,今年10岁
```
3.4 属性继承
实例属性和类属性都可以被继承。
```python
class Base:
class_attr = "基类属性" # 类属性
def init(self):
self.instance_attr = "实例属性"
class Derived(Base):
pass
使用
obj = Derived()
print(obj.class_attr) # 继承类属性: "基类属性"
print(obj.instance_attr) # 继承实例属性: "实例属性"
```
四、访问控制与继承
4.1 Python的访问控制
Python没有严格的访问控制,但有命名约定:
```python
class Parent:
def init(self):
self.public = "公开" # 公开属性
self._protected = "保护" # 保护属性(约定)
self.__private = "私有" # 私有属性(名称修饰)
def public_method(self):
return "公开方法"
def _protected_method(self):
return "保护方法"
def __private_method(self):
return "私有方法"
class Child(Parent):
def test_access(self):
print(self.public) # ✓ 可访问
print(self._protected) # ✓ 可访问(但不建议)
print(self.__private) # ✗ 会报错
print(self._Parent__private) # ✓ 可通过名称修饰访问(不推荐)
print(self.public_method()) # ✓
print(self._protected_method()) # ✓
print(self.__private_method()) # ✗
使用
child = Child()
child.test_access()
```
五、特殊继承场景
5.1 抽象基类(Abstract Base Class)
定义接口规范,子类必须实现抽象方法。
```python
from abc import ABC, abstractmethod
import math
class Shape(ABC): # 抽象基类
@abstractmethod
def area(self):
"""计算面积,子类必须实现"""
pass
@abstractmethod
def perimeter(self):
"""计算周长,子类必须实现"""
pass
def describe(self): # 具体方法
return f"这是一个形状,面积={self.area():.2f},周长={self.perimeter():.2f}"
class Circle(Shape):
def init(self, radius):
self.radius = radius
def area(self): # 实现抽象方法
return math.pi * self.radius ** 2
def perimeter(self): # 实现抽象方法
return 2 * math.pi * self.radius
class Rectangle(Shape):
def init(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
使用
shapes = [Circle(5), Rectangle(4, 6)]
for shape in shapes:
print(shape.describe()) # 多态调用
```
5.2 Mixin类
Mixin是一种特殊的多继承用法,提供可选功能。
```python
Mixin类:通常以Mixin结尾,表示可混入的功能
class JSONSerializableMixin:
def to_json(self):
import json
假设对象有__dict__属性
return json.dumps(self.dict, indent=2)
@classmethod
def from_json(cls, json_str):
import json
data = json.loads(json_str)
return cls(**data)
class XMLSerializableMixin:
def to_xml(self):
简化的XML序列化
xml = f"<{self.class.name}>\n"
for key, value in self.dict.items():
xml += f" <{key}>{value}</{key}>\n"
xml += f"</{self.class.name}>"
return xml
class Person:
def init(self, name, age):
self.name = name
self.age = age
动态组合功能
class Employee(Person, JSONSerializableMixin, XMLSerializableMixin):
def init(self, name, age, employee_id):
super().init(name, age)
self.employee_id = employee_id
使用
emp = Employee("张三", 30, "E001")
print(emp.to_json())
print(emp.to_xml())
```
5.3 菱形继承问题(钻石问题)
多继承可能导致的父类方法被多次调用问题。
```python
class A:
def method(self):
return "A.method()"
class B(A):
def method(self):
return "B.method() -> " + super().method()
class C(A):
def method(self):
return "C.method() -> " + super().method()
class D(B, C): # 菱形继承
def method(self):
return "D.method() -> " + super().method()
Python使用C3线性化算法解决钻石问题
d = D()
print(d.method())
print(f"MRO: {[cls.name for cls in D.mro]}")
输出: D.method() -> B.method() -> C.method() -> A.method()
MRO: ['D', 'B', 'C', 'A', 'object']
```
六、继承的最佳实践
6.1 继承 vs 组合
· 继承:表示"是一个"的关系(is-a)
· 组合:表示"有一个"的关系(has-a)
```python
继承:Car IS A Vehicle
class Vehicle:
pass
class Car(Vehicle): # 继承
pass
组合:Car HAS AN Engine
class Engine:
def start(self):
return "引擎启动"
class Car2: # 组合
def init(self):
self.engine = Engine() # 组合关系
def start(self):
return self.engine.start()
```
6.2 Liskov替换原则
子类对象必须能够替换父类对象,而不影响程序的正确性。
```python
class Bird:
def fly(self):
return "飞"
违反LSP的例子
class Penguin(Bird): # 企鹅是鸟,但不会飞
def fly(self):
raise Exception("企鹅不会飞!") # 违反LSP
遵循LSP的设计
class FlyingBird:
def fly(self):
return "飞"
class NonFlyingBird:
def swim(self):
return "游泳"
class Sparrow(FlyingBird): # 麻雀会飞
pass
class Penguin2(NonFlyingBird): # 企鹅不会飞
pass
```
6.3 避免过深的继承层次
继承层次不宜过深(通常不超过3层),否则会增加代码复杂度。
七、Python特殊方法继承
7.1 __init__方法继承
```python
class Base:
def init(self, value):
self.value = value
print(f"Base.init({value})")
class Derived(Base):
def init(self, value, extra):
super().init(value) # 必须显式调用父类__init__
self.extra = extra
print(f"Derived.init({value}, {extra})")
使用
d = Derived(10, "extra")
```
7.2 运算符重载继承
```python
class Vector:
def init(self, x, y):
self.x = x
self.y = y
def add(self, other):
return Vector(self.x + other.x, self.y + other.y)
def str(self):
return f"Vector({self.x}, {self.y})"
class Vector3D(Vector):
def init(self, x, y, z):
super().init(x, y)
self.z = z
def add(self, other):
调用父类的__add__并扩展
result_2d = super().add(other)
return Vector3D(result_2d.x, result_2d.y, self.z + other.z)
def str(self):
return f"Vector3D({self.x}, {self.y}, {self.z})"
使用
v1 = Vector3D(1, 2, 3)
v2 = Vector3D(4, 5, 6)
print(v1 + v2) # Vector3D(5, 7, 9)
```
八、实际应用示例
8.1 图形界面组件继承
```python
class UIComponent:
def init(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.visible = True
def render(self):
if self.visible:
print(f"渲染组件在({self.x}, {self.y})")
def hide(self):
self.visible = False
def show(self):
self.visible = True
class Button(UIComponent):
def init(self, x, y, width, height, text):
super().init(x, y, width, height)
self.text = text
self.click_handlers = []
def render(self):
if self.visible:
print(f"渲染按钮 '{self.text}' 在({self.x}, {self.y})")
def click(self):
print(f"按钮 '{self.text}' 被点击")
for handler in self.click_handlers:
handler(self)
def add_click_handler(self, handler):
self.click_handlers.append(handler)
class CheckBox(UIComponent):
def init(self, x, y, label, checked=False):
super().init(x, y, 20, 20) # 固定大小
self.label = label
self.checked = checked
def render(self):
status = "✓" if self.checked else "□"
if self.visible:
print(f"{status} {self.label}")
def toggle(self):
self.checked = not self.checked
使用
btn = Button(10, 10, 100, 30, "提交")
btn.add_click_handler(lambda b: print(f"处理按钮点击: {b.text}"))
checkbox = CheckBox(10, 50, "同意条款")
components = [btn, checkbox]
for comp in components:
comp.render()
btn.click()
checkbox.toggle()
checkbox.render()
```
总结
继承是面向对象编程的核心概念,正确使用继承可以:
-
提高代码复用性和可维护性
-
建立清晰的类层次结构
-
支持多态,增加程序灵活性
-
通过抽象基类定义接口规范
但也要注意:
-
避免过深的继承层次
-
优先使用组合而非继承(当不确定时)
-
遵循Liskov替换原则
-
合理使用抽象基类和Mixin