Python 入门实践 09:类、对象、继承与组合
系列第 9 篇:本文是《Python编程 从入门到实践》读书笔记系列的第 9 篇。
本文内容:类的创建与实例化、类属性与方法的定义、继承(super()、重写)、组合(将实例用作属性)、导入类、Python 标准库。
本章目标:这一篇主要解决一个问题:当程序里出现"有属性、有行为的对象"时,怎么组织代码更清楚。
开篇:这篇解决什么问题
函数适合封装动作,字典适合保存数据。类则适合把数据和动作放在一起,比如任务对象、用户对象、订单对象。这样代码更接近我们描述业务的方式。
本篇你会学到什么
- 类和对象分别是什么
__init__()和self怎么理解- 如何给类添加属性和方法
- 如何修改对象属性
- 继承和组合分别适合什么场景
场景案例:定义一个自动化任务对象
先定义一个任务类:
python
class AutomationTask:
"""A simple automation task."""
def __init__(self, name, owner):
self.name = name
self.owner = owner
self.status = 'pending'
def describe(self):
print(self.name + ' is owned by ' + self.owner + '.')
def run(self):
self.status = 'running'
print('Run task: ' + self.name)
task = AutomationTask('daily_report', 'alice')
task.describe()
task.run()
print(task.status)
这个例子里,任务有名称、负责人、状态,也有描述和运行两个动作。这就是类适合表达的东西。
知识点拆解
1. 创建类
python
class Dog:
"""A simple dog class."""
def __init__(self, name, age):
self.name = name
self.age = age
def sit(self):
print(self.name.title() + ' is now sitting.')
类名通常使用大驼峰命名,比如 Dog、UserProfile、AutomationTask。
2. __init__() 是初始化方法
创建实例时,Python 会自动调用 __init__():
python
my_dog = Dog('willie', 6)
这里 'willie' 和 6 会传给 name 和 age,然后保存到实例属性里。
3. self 表示当前实例
python
self.name = name
self.age = age
可以简单理解为:把传进来的值,保存到"当前这个对象"身上。
初学时不用把 self 想得太玄。先记住:类里的方法第一个参数通常写 self,通过 self.xxx 访问对象自己的属性。
4. 创建实例并访问属性
python
my_dog = Dog('willie', 6)
print(my_dog.name)
print(my_dog.age)
调用方法:
python
my_dog.sit()
5. 给属性设置默认值
python
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def read_odometer(self):
print('This car has ' + str(self.odometer_reading) + ' miles on it.')
odometer_reading 不需要从外部传入,新车默认里程为 0。
6. 修改属性
可以直接修改:
python
my_car = Car('audi', 'a4', 2024)
my_car.odometer_reading = 100
my_car.read_odometer()
也可以通过方法修改:
python
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def update_odometer(self, mileage):
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer.")
通过方法修改属性,可以加一些校验逻辑。
7. 继承:子类复用父类能力
python
class ElectricCar(Car):
def __init__(self, make, model, year):
super().__init__(make, model, year)
self.battery_size = 75
def describe_battery(self):
print('This car has a ' + str(self.battery_size) + '-kWh battery.')
ElectricCar 继承了 Car 的属性和方法,又增加了电池容量。
继承适合表达"某类对象是一种更具体的对象"。比如电动车是一种车。
8. 重写父类方法
如果子类不想使用父类的某个方法,可以重新定义同名方法:
python
class ElectricCar(Car):
def __init__(self, make, model, year):
super().__init__(make, model, year)
def fill_gas_tank(self):
print("This car doesn't need a gas tank.")
9. 组合:把对象作为属性
有时候不用继承,而是把一个对象放到另一个对象里:
python
class Battery:
def __init__(self, battery_size=75):
self.battery_size = battery_size
def describe_battery(self):
print('This car has a ' + str(self.battery_size) + '-kWh battery.')
class ElectricCar(Car):
def __init__(self, make, model, year):
super().__init__(make, model, year)
self.battery = Battery()
组合适合表达"某个对象拥有另一个对象"。比如电动车有一块电池。
10. 导入类
可以把类放在单独文件里,比如 task.py:
python
class AutomationTask:
def __init__(self, name):
self.name = name
在另一个文件里导入:
python
from task import AutomationTask
task = AutomationTask('daily_report')
print(task.name)
初学者容易踩的坑
| 问题 | 常见原因 | 建议 |
|---|---|---|
忘记 self |
方法定义不完整 | 实例方法第一个参数写 self |
__init__ 拼错 |
下划线数量不对 | 前后都是两个下划线 |
| 类名和实例名混乱 | 没分清模板和具体对象 | 类是模板,实例是具体对象 |
| 继承用得太早 | 为了复用而强行继承 | 先判断是不是 "is-a" 关系 |
| 类太大 | 什么逻辑都塞进一个类 | 按职责拆分方法或组合对象 |
工作里能怎么用
| 场景 | 类可以怎么用 |
|---|---|
| 任务对象 | 名称、状态、负责人、执行方法 |
| 用户对象 | 用户名、角色、权限 |
| 配置对象 | 加载、校验、保存配置 |
| 接口客户端 | 请求地址、认证信息、请求方法 |
| 项目实体 | 需求、任务、版本、发布记录 |
示例:任务对象状态流转:
python
class Task:
def __init__(self, name):
self.name = name
self.status = 'pending'
def finish(self):
self.status = 'done'
task = Task('daily_report')
task.finish()
print(task.status)
小结
- 类是模板,实例是根据类创建出来的具体对象
__init__()用来初始化实例属性self表示当前实例- 方法是定义在类里的函数
- 属性可以直接修改,也可以通过方法修改
- 继承适合 "is-a" 关系
- 组合适合 "has-a" 关系
- 类适合组织有属性、有行为的业务对象
下一篇
下一篇继续讲文件读写和异常处理。对象能组织程序结构,文件读写能让程序保存数据,异常处理能让程序更稳。