第 11 章 面向对象编程
学习目标
- 理解类与对象的关系
- 会用
__init__初始化实例属性,会定义方法 - 理解类属性与实例属性的区别
- 掌握继承与
super(),会重写方法 - 知道什么时候该用面向对象
11.1 类与对象
类(class) 是数据与行为的模板,对象(实例) 是根据模板创建的具体个体。比如 Student 是类,「小明」这个具体学生是对象。
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
def greet(self):
return f"我是{self.name},成绩{self.score}分"
s = Student("小明", 92)
print(s.name)
print(s.score)
print(s.greet())输出:
小明
92
我是小明,成绩92分语法要点:
class Student:定义类,类名习惯用大驼峰命名(每个单词首字母大写,如BankAccount)。__init__是初始化方法,创建对象时自动调用,用来给对象设置初始属性。self指当前创建的这个对象本身,self.name = name把参数存到对象上,成为实例属性。greet是方法,定义时第一个参数必须是self,调用时不需要传(如s.greet())。
11.2 类属性与实例属性
实例属性属于某个具体对象(通过 self.xxx 赋值);类属性定义在类内部、方法之外,属于整个类,所有对象共享:
class Student:
school = "第一中学" # 类属性
def __init__(self, name):
self.name = name # 实例属性
print(Student.school) # 通过类访问
s = Student("小红")
print(s.school) # 对象也能访问类属性输出:
第一中学
第一中学类属性适合保存「所有对象都相同」的信息,如学校名、班级号。
11.3 继承
继承让一个新类自动获得已有类的属性和方法,并可以补充或改写。新类叫子类,被继承的叫父类:
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return "..."
class Dog(Animal):
def speak(self):
return "汪汪"
d = Dog("旺财")
print(d.name)
print(d.speak())输出:
旺财
汪汪Dog(Animal) 表示 Dog 继承 Animal:name 属性和 __init__ 直接继承,speak 被重写(override)成自己的版本。
子类要扩展父类的初始化,用 super() 调用父类的方法:
class Animal:
def __init__(self, name):
self.name = name
class Dog(Animal):
def __init__(self, name, age):
super().__init__(name) # 先执行父类的 __init__
self.age = age
d = Dog("旺财", 3)
print(d.name, d.age)输出:
旺财 311.4 特殊方法
特殊方法是名字以双下划线开头和结尾的方法,Python 在特定时机自动调用。最常见的是 __init__;另一个常用的是 __str__,它决定 print(对象) 时显示什么:
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
def __str__(self):
return f"Student({self.name}, {self.score})"
s = Student("小明", 92)
print(s)输出:
Student(小明, 92)没有 __str__ 时,print(s) 会显示类似 <__main__.Student object at 0x...> 的内存地址。给类加上 __str__ 能让调试输出一目了然。
11.5 什么时候用面向对象
面向对象不是必须的。判断标准:有没有一组「数据 + 对这些数据的操作」需要被反复使用。
适合用类的例子:银行账户(余额 + 存取款)、学生(信息 + 打招呼)、商品(价格 + 折扣)。这些场景里,把数据和行为打包成一个类,比用散落的列表和函数更清晰。
不适合的场景:只是算个数、处理一次数据,用函数就够了。第 7 章的函数写法与本章的类写法是两种工具,按需选用,不必强行面向对象。
动手实践
任务:银行账户。 实现一个 BankAccount 类,支持开户、存款、取款,并处理非法操作:
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self.balance = balance
def deposit(self, amount):
if amount <= 0:
return "金额必须大于 0"
self.balance += amount
return f"存入 {amount},余额 {self.balance}"
def withdraw(self, amount):
if amount > self.balance:
return "余额不足"
self.balance -= amount
return f"取出 {amount},余额 {self.balance}"
def __str__(self):
return f"{self.owner} 的账户,余额 {self.balance}"
acc = BankAccount("小明", 100)
print(acc)
print(acc.deposit(50))
print(acc.withdraw(200))
print(acc.withdraw(30))输出:
小明 的账户,余额 100
存入 50,余额 150
余额不足
取出 30,余额 120注意:取款超过余额和存入非正数都被方法「拦截」返回提示,而不是把余额改成错误值——这正是把操作封装进类的价值。
常见错误
| 错误写法 | 报错信息 | 原因 |
|---|---|---|
def method(): 忘了 self | TypeError: A.method() takes 0 positional arguments but 1 was given | 实例方法第一个参数必须是 self |
def __int__(self, ...) | 创建对象时不报错,但属性没初始化 | __init__ 拼写错误,__int__ 是另一个特殊方法 |
__init__ 里 name = name 忘写 self. | 属性没有被保存到对象上 | 保存实例属性必须写 self.name = name |
调用方法时多写一个参数 s.greet(s) | TypeError: greet() takes 1 positional argument but 2 were given | self 由 Python 自动传入,不要手动传 |
子类 __init__ 忘了 super().__init__(...) | 不报错但父类属性未初始化 | 需要父类属性时调用 super().__init__() |
章末练习
基础
- 定义类
Book,有属性title、author和price;创建一本书并打印三个属性。 - 给
Book加方法info(),返回"《书名》- 作者"格式的字符串,调用验证。 - 给
Book加__str__,让print(book)输出"《Python 入门》- 张三,定价 59 元"这样的格式。
提高
- 定义
Animal父类(属性name,方法speak()返回"..."),再定义子类Cat和Dog,分别重写speak(),创建对象并输出各自叫声。 - 定义
Rectangle类,属性为宽和高,方法area()返回面积;再定义子类Square,用super().__init__(side, side)复用父类初始化,验证边长为 4 的正方形面积为 16。
挑战
- 在「银行账户」基础上增加:统计该账户的交易次数属性
count(每次成功存取 +1),并增加方法show_count()输出次数。 - 思考并回答:下面的需求用类还是函数更合适?说明理由——「一个程序要管理 5 个学生的姓名和成绩,并计算每个学生的平均分」。
章末自测
每题选择一个最佳答案。本书不附答案:完成后交由老师或 AI 老师批改讲解。
- 根据模板创建的具体个体叫?
- A. 类
- B. 对象
- C. 函数
- D. 模块
__init__方法的作用是?- A. 删除对象
- B. 创建对象时初始化属性
- C. 输出对象
- D. 定义类
- 实例方法定义的第一个参数必须是?
- A.
this - B.
self - C.
cls - D. 没有要求
- A.
self.name = name的作用是?- A. 比较两个名字
- B. 把 name 保存为对象的实例属性
- C. 定义类属性
- D. 调用方法
- 类属性与实例属性的区别是?
- A. 类属性所有对象共享
- B. 实例属性所有对象共享
- C. 没有区别
- D. 类属性只能读不能写
class Dog(Animal):表示?- A. Animal 继承 Dog
- B. Dog 继承 Animal
- C. Dog 与 Animal 无关
- D. Dog 复制 Animal
- 子类中重写父类方法的含义是?
- A. 删除父类方法
- B. 定义同名方法覆盖父类版本
- C. 复制父类方法
- D. 报错
super().__init__(name)的作用是?- A. 创建新对象
- B. 调用父类的初始化方法
- C. 调用子类方法
- D. 删除对象
__str__方法决定?- A. 对象是否可删除
- B.
print(对象)显示的内容 - C. 对象的内存地址
- D. 对象的类型
- 下列哪种场景最适合用类? A. 计算 1+1 B. 银行账户(余额 + 存取操作) C. 打印一行文字 D. 读一个文件
