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