> 如果你只会面向过程写 Python,那你只用出了它 50% 的威力。今天聊聊什么是面向对象编程。
---
## 一、为什么要学面向对象?
想象一下:
-**面向过程**:做一顿饭,从洗菜、切菜、炒菜到摆盘,一步一步写到底
-**面向对象**:你有 `厨师`、`切菜机`、`燃气灶` 这些"对象",每个对象自带方法,你只需要协调它们
随着程序变大,面向对象的 **可维护性、复用性、扩展性** 优势就体现出来了。
---
## 二、类与对象的基本概念
### 2.1 定义一个类
```python
classDog:
"""代表一只狗"""
# 类属性(所有实例共享)
species = "Canis familiaris"
# 构造方法
def__init__(self, name, age):
# 实例属性(每个实例独立)
self.name = name
self.age = age
# 实例方法
defbark(self):
returnf"{self.name} 说:汪汪汪!"
defget_info(self):
returnf"{self.name},{self.age}岁,{self.species}"
# 创建对象(实例)
dog1 = Dog("小白", 3)
dog2 = Dog("小黑", 5)
print(dog1.bark()) # 小白 说:汪汪汪!
print(dog2.get_info()) # 小黑,5岁,Canis familiaris
```
>**关键理解**:
>-`class Dog` 定义了模板
>-`__init__` 是构造函数,实例化时自动调用
>-`self` 指向实例本身(类似 JavaScript 的 `this`,Java 的 `this`)
>- 实例方法第一个参数必须是 `self`
### 2.2 类属性 vs 实例属性
```python
classCompany:
company_name = "ABC科技"# 类属性
def__init__(self, employee_name):
self.employee_name = employee_name # 实例属性
emp1 = Company("张三")
emp2 = Company("李四")
print(emp1.company_name) # ABC科技(类属性)
print(emp1.employee_name) # 张三(实例属性)
print(emp2.employee_name) # 李四(实例属性)
# 修改类属性会影响所有实例
Company.company_name = "XYZ集团"
print(emp1.company_name) # XYZ集团
```
---
## 三、封装——隐藏内部细节
### 3.1 基本的封装
```python
classBankAccount:
"""银行账户"""
def__init__(self, owner, balance=0):
self.owner = owner
self.__balance = balance # 私有属性(以双下划线开头)
defdeposit(self, amount):
"""存款"""
if amount > 0:
self.__balance += amount
print(f"存入 ¥{amount},余额:¥{self.__balance}")
else:
print("存款金额必须大于 0")
defwithdraw(self, amount):
"""取款"""
if amount > self.__balance:
print("余额不足!")
elif amount > 0:
self.__balance -= amount
print(f"取出 ¥{amount},余额:¥{self.__balance}")
else:
print("取款金额必须大于 0")
defget_balance(self):
"""查看余额(提供安全的访问方式)"""
returnself.__balance
# 测试
account = BankAccount("张三", 1000)
account.deposit(500)
account.withdraw(300)
print(account.get_balance()) # 1200
# 尝试直接访问私有属性(Python 不是真正的私有,只是改名隐藏)
# print(account.__balance) # AttributeError!
print(account._BankAccount__balance) # 1200(不建议这样做)
```
### 3.2@property 装饰器
```python
classStudent:
"""学生类,带成绩验证"""
def__init__(self, name):
self.name = name
self.__score = 0
@property
defscore(self):
"""读取分数"""
returnself.__score
@score.setter
defscore(self, value):
"""设置分数(带验证)"""
if0 <= value <= 100:
self.__score = value
else:
raiseValueError("分数必须在 0-100 之间")
@property
defgrade(self):
"""根据分数自动计算等级"""
ifself.__score >= 90:
return"优秀"
elifself.__score >= 80:
return"良好"
elifself.__score >= 60:
return"及格"
else:
return"不及格"
# 测试
student = Student("李四")
student.score = 85
print(f"{student.name}的分数: {student.score},等级: {student.grade}")
# 李四的分数: 85,等级: 良好
student.score = 150# ValueError: 分数必须在 0-100 之间
```
---
## 四、继承——站在巨人的肩膀上
### 4.1 单继承
```python
# 基类(父类)
classAnimal:
def__init__(self, name, age):
self.name = name
self.age = age
defspeak(self):
return"我不知道发出什么声音..."
definfo(self):
returnf"{self.name},{self.age}岁"
# 派生类(子类)
classCat(Animal):
def__init__(self, name, age, color):
super().__init__(name, age) # 调用父类的 __init__
self.color = color
defspeak(self):
return"喵喵喵~"
definfo(self):
# 扩展父类的方法
returnf"{super().info()},{self.color}"
# 测试
cat = Cat("咪咪", 3, "橘色")
print(cat.speak()) # 喵喵喵~
print(cat.info()) # 咪咪,3岁,橘色
```
### 4.2 方法重写与多态
```python
classAnimal:
def__init__(self, name):
self.name = name
defspeak(self):
raiseNotImplementedError("子类必须实现此方法")
def__str__(self):
returnf"动物: {self.name}"
classDog(Animal):
defspeak(self):
return"汪汪汪!"
classCat(Animal):
defspeak(self):
return"喵喵喵~"
classDuck(Animal):
defspeak(self):
return"嘎嘎嘎~"
# 多态:不同对象对同一方法做出不同响应
animals = [Dog("旺财"), Cat("咪咪"), Duck("嘎嘎")]
for animal in animals:
print(f"{animal}说: {animal.speak()}")
# 动物: 旺财说: 汪汪汪!
# 动物: 咪咪说: 喵喵喵~
# 动物: 嘎嘎说: 嘎嘎嘎~
```
### 4.3 多重继承
```python
classSwimmer:
defswim(self):
return"我会游泳!"
classFlyer:
deffly(self):
return"我会飞翔!"
classDuck(Swimmer, Flyer, Animal):
"""鸭子继承了三个父类的特性"""
pass
duck = Duck("唐老鸭")
print(duck.speak()) # 嘎嘎嘎~(来自Animal)
print(duck.swim()) # 我会游泳!(来自Swimmer)
print(duck.fly()) # 我会飞翔!(来自Flyer)
```
>**注意**:多重继承容易引起"菱形问题",Python 使用 MRO(Method Resolution Order)来解决。
> 用 `类名.__mro__` 可以查看方法的解析顺序。
---
## 五、魔术方法(Dunder Methods)
以双下划线开头和结尾的方法,Python 会自动调用它们。
### 5.1 常用魔术方法
```python
classRectangle:
"""矩形类"""
def__init__(self, width, height):
self.width = width
self.height = height
def__str__(self):
"""print() 调用的字符串表示"""
returnf"矩形({self.width} x {self.height})"
def__repr__(self):
"""开发者友好的字符串表示"""
returnf"Rectangle(width={self.width}, height={self.height})"
def__len__(self):
"""len() 调用的长度"""
returnint((self.width ** 2 + self.height ** 2) ** 0.5) # 对角线长度
def__lt__(self, other):
"""小于比较(按面积)"""
returnself.area() < other.area()
def__le__(self, other):
"""小于等于"""
returnself.area() <= other.area()
def__eq__(self, other):
"""相等比较"""
ifnotisinstance(other, Rectangle):
returnNotImplemented
returnself.area() == other.area()
def__add__(self, other):
"""加法:两个矩形合并"""
return Rectangle(self.width + other.width, self.height + other.height)
defarea(self):
returnself.width * self.height
# 测试
rect1 = Rectangle(3, 4)
rect2 = Rectangle(5, 6)
rect3 = Rectangle(2, 7.5)
print(rect1) # 矩形(3 x 4)
print(repr(rect2)) # Rectangle(width=5, height=6)
print(len(rect1)) # 5(对角线)
print(rect1 < rect2) # True(面积 12 < 30)
print(rect2 == rect3) # True(面积都是 30)
rect4 = rect1 + rect2
print(rect4) # 矩形(8 x 10)
```
### 5.2 让类可迭代
```python
classFibonacci:
"""斐波那契数列生成器(支持迭代)"""
def__init__(self, count=10):
self.count = count
def__iter__(self):
self._a, self._b = 0, 1
self._index = 0
returnself
def__next__(self):
ifself._index >= self.count:
raiseStopIteration
self._index += 1
result = self._a
self._a, self._b = self._b, self._a + self._b
return result
# 使用
fib = Fibonacci(10)
for num in fib:
print(num, end=" ")
# 0 1 1 2 3 5 8 13 21 34
```
---
## 六、类方法与静态方法
```python
classMathUtils:
PI = 3.1415926535
def__init__(self, radius):
self.radius = radius
# 实例方法(正常方法)
defarea(self):
return MathUtils.PI * self.radius ** 2
# 类方法:操作类属性,可以用类名直接调用
@classmethod
defset_pi(cls, value):
cls.PI = value
print(f"PI 已设置为 {value}")
# 静态方法:既不需要self也不需要cls,只是放在类里的工具函数
@staticmethod
defis_positive(number):
return number > 0
@staticmethod
defcircle_circumference(radius):
return2 * MathUtils.PI * radius
# 测试
utils = MathUtils(5)
print(utils.area()) # 78.53981633750001
print(MathUtils.circle_circumference(5)) # 31.415926535
MathUtils.set_pi(3.1416)
utils2 = MathUtils(10)
print(utils2.area()) # 314.16
print(MathUtils.is_positive(-5)) # False
print(MathUtils.is_positive(3)) # True
```
---
## 七、抽象类
```python
from abc importABC, abstractmethod
classShape(ABC):
"""图形抽象基类"""
@abstractmethod
defarea(self):
pass
@abstractmethod
defperimeter(self):
pass
defdescription(self):
returnf"这是一个{self.__class__.__name__}"
# 下面不实现area和perimeter会报错
classCircle(Shape):
def__init__(self, radius):
self.radius = radius
defarea(self):
return3.14159 * self.radius ** 2
defperimeter(self):
return2 * 3.14159 * self.radius
classSquare(Shape):
def__init__(self, side):
self.side = side
defarea(self):
returnself.side ** 2
defperimeter(self):
return4 * self.side
# 测试
circle = Circle(5)
square = Square(4)
print(circle.description()) # 这是一个Circle
print(f"圆面积: {circle.area():.2f}")
print(f"正方形周长: {square.perimeter()}")
# 不能实例化抽象类
# s = Shape() # TypeError!
```
---
## 八、实战项目:简易银行账户系统
```python
from abc importABC, abstractmethod
from datetime import datetime
classAccount(ABC):
"""账户抽象基类"""
_next_account_no = 1000
def__init__(self, owner, balance=0):
Account._next_account_no += 1
self.account_no = Account._next_account_no
self.owner = owner
self.balance = balance
self.transactions = []
self._record_transaction(f"开户,初始余额: ¥{balance}")
def_record_transaction(self, description):
"""记录交易"""
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.transactions.append({
"time": timestamp,
"description": description
})
@abstractmethod
defwithdraw(self, amount):
pass
@abstractmethod
defdeposit(self, amount):
pass
defstatement(self):
"""生成账单"""
print(f"\n{'='*50}")
print(f" 账户持有人: {self.owner}")
print(f" 账号: {self.account_no}")
print(f" 当前余额: ¥{self.balance:.2f}")
print(f"{'='*50}")
print(" 交易记录:")
for txn inself.transactions:
print(f" [{txn['time']}] {txn['description']}")
print()
classSavingsAccount(Account):
"""储蓄账户"""
def__init__(self, owner, balance=0, interest_rate=0.03):
super().__init__(owner, balance)
self.interest_rate = interest_rate
defdeposit(self, amount):
if amount > 0:
self.balance += amount
self._record_transaction(f"存款 ¥{amount:.2f}")
print(f"✅ 成功存入 ¥{amount:.2f}")
else:
print("❌ 存款金额必须大于 0")
defwithdraw(self, amount):
if amount > 0:
if amount <= self.balance:
self.balance -= amount
self._record_transaction(f"取款 ¥{amount:.2f}")
print(f"✅ 成功取出 ¥{amount:.2f}")
else:
print("❌ 余额不足!")
else:
print("❌ 取款金额必须大于 0")
defadd_interest(self):
"""计算利息"""
interest = self.balance * self.interest_rate
self.balance += interest
self._record_transaction(f"利息 ¥{interest:.2f}")
print(f"🏦 利息 ¥{interest:.2f} 已入账")
classCheckingAccount(Account):
"""支票账户(允许透支)"""
OVERDRAFT_LIMIT = 5000
defdeposit(self, amount):
if amount > 0:
self.balance += amount
self._record_transaction(f"存款 ¥{amount:.2f}")
print(f"✅ 成功存入 ¥{amount:.2f}")
defwithdraw(self, amount):
if amount > 0:
if amount <= self.balance + self.OVERDRAFT_LIMIT:
self.balance -= amount
self._record_transaction(f"取款 ¥{amount:.2f}")
ifself.balance < 0:
print(f"⚠️ 成功取出 ¥{amount:.2f},当前已透支 ¥{abs(self.balance):.2f}")
else:
print(f"✅ 成功取出 ¥{amount:.2f}")
else:
print(f"❌ 超出透支限额!最大可透支 ¥{self.OVERDRAFT_LIMIT}")
else:
print("❌ 取款金额必须大于 0")
# ============ 演示 ============
print("🏦 创建储蓄账户...")
savings = SavingsAccount("张三", 10000, 0.05)
savings.deposit(5000)
savings.withdraw(3000)
print("\n🏦 创建支票账户...")
checking = CheckingAccount("李四", 2000)
checking.deposit(10000)
checking.withdraw(15000) # 允许透支
print("\n📋 查看储蓄账户账单...")
savings.statement()
print("\n📋 查看支票账户账单...")
checking.statement()
```
运行效果:
```
🏦 创建储蓄账户...
✅ 成功存入 ¥5000.00
✅ 成功取出 ¥3000.00
🏦 创建支票账户...
✅ 成功存入 ¥10000.00
⚠️ 成功取出 ¥15000.00,当前已透支 ¥5000.00
📋 查看储蓄账户账单...
==================================================
账户持有人: 张三
账号: 1002
当前余额: ¥12000.00
==================================================
交易记录:
[2026-07-02 14:00:00] 开户,初始余额: ¥10000
[2026-07-02 14:00:00] 存款 ¥5000.00
[2026-07-02 14:00:00] 取款 ¥3000.00
```
---
## 九、OOP 核心原则回顾
### 三大支柱
| 原则 | 说明 | 本课对应 |
|------|------|---------|
| **封装** | 隐藏内部实现,对外暴露安全接口 | `__balance`、`@property` |
| **继承** | 子类继承父类的属性和方法 | `class Dog(Animal)` |
| **多态** | 不同对象对同一消息有不同反应 | 不同动物调用 `speak()` |
### 额外补充:抽象
-**抽象基类**(`ABC`)定义接口规范
- 子类必须实现抽象方法
- 保证接口的一致性
---
## 十、练习题
### 练习 1:学生成绩管理类
```python
classStudent:
def__init__(self, name):
self.name = name
self.scores = {}
defadd_score(self, subject, score):
if0 <= score <= 100:
self.scores[subject] = score
defaverage(self):
ifnotself.scores:
return0
returnsum(self.scores.values()) / len(self.scores)
defgrade(self):
avg = self.average()
if avg >= 90: return"A"
elif avg >= 80: return"B"
elif avg >= 70: return"C"
elif avg >= 60: return"D"
else: return"F"
stu = Student("王五")
stu.add_score("数学", 95)
stu.add_score("英语", 87)
print(f"平均分: {stu.average():.1f}, 等级: {stu.grade()}")
```
### 练习 2:链表节点
```python
classNode:
def__init__(self, data):
self.data = data
self.next = None
classLinkedList:
def__init__(self):
self.head = None
defappend(self, data):
new_node = Node(data)
ifnotself.head:
self.head = new_node
return
current = self.head
while current.next:
current = current.next
current.next = new_node
defdisplay(self):
nodes = []
current = self.head
while current:
nodes.append(str(current.data))
current = current.next
print(" -> ".join(nodes) + " -> None")
ll = LinkedList()
ll.append(10)
ll.append(20)
ll.append(30)
ll.display() # 10 -> 20 -> 30 -> None
```
### 练习 3:继承层次设计
设计一个图形库,包含:
-`Shape`(抽象基类)
-`Circle`、`Rectangle`、`Triangle`(子类)
- 每个子类实现 `area()` 和 `perimeter()` 方法
- 测试各种图形的面积和周长
### 练习 4:宠物店模拟器
```python
classPet:
def__init__(self, name, species):
self.name = name
self.species = species
self.hunger = 50
self.happiness = 50
deffeed(self):
self.hunger -= 20
self.happiness += 10
print(f"{self.name} 吃了东西!饥饿: {self.hunger}, 快乐: {self.happiness}")
defplay(self):
self.happiness += 30
self.hunger += 10
print(f"{self.name} 玩了玩具!饥饿: {self.hunger}, 快乐: {self.happiness}")
pet = Pet("豆豆", "狗狗")
pet.feed()
pet.play()
```
### 练习 5:图书馆管理系统
```python
classBook:
def__init__(self, title, author, isbn):
self.title = title
self.author = author
self.isbn = isbn
self.is_borrowed = False
classLibrary:
def__init__(self):
self.books = []
defadd_book(self, book):
self.books.append(book)
print(f"📚 添加了《{book.title}》")
defborrow_book(self, isbn):
for book inself.books:
if book.isbn == isbn:
if book.is_borrowed:
print("此书已被借出")
else:
book.is_borrowed = True
print(f"✅ 借走了《{book.title}》")
return
print("❌ 未找到该书")
defreturn_book(self, isbn):
for book inself.books:
if book.isbn == isbn:
book.is_borrowed = False
print(f"📖 归还了《{book.title}》")
return
print("❌ 未找到该书")
lib = Library()
lib.add_book(Book("Python编程", "作者A", "978-7"))
lib.borrow_book("978-7")
lib.return_book("978-7")
```
---
## 下期预告
**Python 教程 Episode 04 — 装饰器、生成器与文件IO**
- 装饰器:在不修改原函数的前提下扩展功能(带参数的装饰器、@functools.wraps)
- 生成器:yield 的工作原理,内存高效的无限序列
- 文件读写:open() 的几种模式、with 语句、CSV/JSON 处理
- 异常处理:try-except-else-finally 完整结构
- 实战:用装饰器实现函数计时器和用生成器处理大文件
---
*如果觉得本系列对你有帮助,欢迎点赞、评论、转发!有任何问题,在留言区讨论。*