类和对象

python学习

一、继承的基本概念

继承是面向对象编程的三大特性之一(封装、继承、多态),它允许我们定义一个类(子类)来继承另一个类(父类)的属性和方法。

1. 基本语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class ParentClass:
"""父类/基类"""
def parent_method(self):
print("这是父类方法")

class ChildClass(ParentClass):
"""子类/派生类"""
def child_method(self):
print("这是子类方法")

# 使用示例
child = ChildClass()
child.parent_method() # 调用继承的方法
child.child_method() # 调用子类自己的方法

2. 继承的特性

  • 子类继承父类的所有公有属性和方法
  • 子类可以扩展父类的功能
  • 子类可以重写父类的方法
  • 子类的实例也是父类的实例(isinstance 返回 True

二、方法重写(Override)

子类可以重新定义父类的方法,这称为方法重写。

1. 完全重写

1
2
3
4
5
6
7
8
9
10
11
class Animal:
def speak(self):
print("动物发出声音")

class Dog(Animal):
def speak(self): # 完全重写父类方法
print("汪汪汪!")

# 使用示例
dog = Dog()
dog.speak() # 输出: 汪汪汪!

2. 扩展父类方法(使用 super())

1
2
3
4
5
6
7
8
9
10
11
12
class Animal:
def __init__(self, name):
self.name = name

class Cat(Animal):
def __init__(self, name, color):
super().__init__(name) # 调用父类的初始化方法
self.color = color # 添加新的属性

# 使用示例
cat = Cat("咪咪", "白色")
print(f"名字: {cat.name}, 颜色: {cat.color}")

三、多重继承

Python 支持多重继承,即一个类可以继承多个父类。

1. 基本语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Father:
def father_method(self):
print("父亲的方法")

class Mother:
def mother_method(self):
print("母亲的方法")

class Child(Father, Mother): # 继承多个父类
def child_method(self):
print("孩子的方法")

# 使用示例
child = Child()
child.father_method() # 调用Father的方法
child.mother_method() # 调用Mother的方法
child.child_method() # 调用自己的方法

2. 方法解析顺序(MRO)

当多个父类有同名方法时,Python 使用 C3 算法确定调用顺序,可以通过 类名.__mro__ 查看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class A:
def method(self):
print("A的方法")

class B(A):
def method(self):
print("B的方法")

class C(A):
def method(self):
print("C的方法")

class D(B, C):
pass

print(D.__mro__) # 查看方法解析顺序
# 输出: (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

d = D()
d.method() # 输出: B的方法

3. 菱形继承问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class A:
def method(self):
print("A的方法")

class B(A):
def method(self):
print("B的方法")
super().method() # 调用下一个类的方法

class C(A):
def method(self):
print("C的方法")
super().method()

class D(B, C):
def method(self):
print("D的方法")
super().method()

# 方法调用顺序: D -> B -> C -> A
d = D()
d.method()
"""
输出:
D的方法
B的方法
C的方法
A的方法
"""

四、特殊方法与继承

1. __init__ 方法的继承

1
2
3
4
5
6
7
8
9
10
11
12
class Person:
def __init__(self, name):
self.name = name

class Student(Person):
def __init__(self, name, student_id):
super().__init__(name) # 调用父类的__init__
self.student_id = student_id

# 使用示例
student = Student("张三", "2023001")
print(student.name, student.student_id)

2. 其他特殊方法的重写

1
2
3
4
5
6
7
class MyList(list):  # 继承内置list类
def __str__(self):
# 重写__str__方法
return f"MyList: {super().__str__()}"

lst = MyList([1, 2, 3])
print(lst) # 输出: MyList: [1, 2, 3]

五、抽象基类与接口

Python 通过 abc 模块支持抽象基类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from abc import ABC, abstractmethod

class Shape(ABC): # 抽象基类
@abstractmethod
def area(self):
pass

@abstractmethod
def perimeter(self):
pass

class Circle(Shape):
def __init__(self, radius):
self.radius = radius

def area(self): # 必须实现抽象方法
return 3.14 * self.radius ** 2

def perimeter(self):
return 2 * 3.14 * self.radius

# 使用示例
circle = Circle(5)
print(circle.area()) # 输出: 78.5

六、继承的最佳实践

  1. 优先使用组合而非继承:除非确实是”is-a”关系
  2. 避免深度继承:继承层次不宜过深
  3. 合理使用多重继承:谨慎设计,避免复杂关系
  4. 使用抽象基类定义接口:明确子类需要实现的方法
  5. 遵循LSP原则:子类应该能够替换父类

七、完整示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 多重继承综合示例
class Animal:
def __init__(self, name):
self.name = name

def eat(self):
print(f"{self.name}正在吃东西")

class Flyable:
def fly(self):
print(f"{self.name}正在飞翔")

class Swimable:
def swim(self):
print(f"{self.name}正在游泳")

class Bird(Animal, Flyable):
def __init__(self, name):
super().__init__(name)

def speak(self):
print(f"{self.name}在唱歌")

class Duck(Bird, Swimable):
def __init__(self, name):
super().__init__(name)

def speak(self): # 重写父类方法
print(f"{self.name}在嘎嘎叫")

# 使用示例
duck = Duck("唐老鸭")
duck.eat() # 继承自Animal
duck.fly() # 继承自Flyable
duck.swim() # 继承自Swimable
duck.speak() # 调用重写后的方法