Skip to content

第 11 章 面向对象编程

学习目标

  • 理解类与对象的关系
  • 会用 __init__ 初始化实例属性,会定义方法
  • 理解类属性与实例属性的区别
  • 掌握继承与 super(),会重写方法
  • 知道什么时候该用面向对象

11.1 类与对象

类(class) 是数据与行为的模板,对象(实例) 是根据模板创建的具体个体。比如 Student 是类,「小明」这个具体学生是对象。

python
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分

语法要点:

  1. class Student: 定义类,类名习惯用大驼峰命名(每个单词首字母大写,如 BankAccount)。
  2. __init__初始化方法,创建对象时自动调用,用来给对象设置初始属性。self 指当前创建的这个对象本身,self.name = name 把参数存到对象上,成为实例属性
  3. greet方法,定义时第一个参数必须是 self,调用时不需要传(如 s.greet())。

11.2 类属性与实例属性

实例属性属于某个具体对象(通过 self.xxx 赋值);类属性定义在类内部、方法之外,属于整个类,所有对象共享:

python
class Student:
    school = "第一中学"      # 类属性

    def __init__(self, name):
        self.name = name     # 实例属性

print(Student.school)        # 通过类访问
s = Student("小红")
print(s.school)              # 对象也能访问类属性

输出:

第一中学
第一中学

类属性适合保存「所有对象都相同」的信息,如学校名、班级号。

11.3 继承

继承让一个新类自动获得已有类的属性和方法,并可以补充或改写。新类叫子类,被继承的叫父类:

python
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() 调用父类的方法:

python
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)

输出:

旺财 3

11.4 特殊方法

特殊方法是名字以双下划线开头和结尾的方法,Python 在特定时机自动调用。最常见的是 __init__;另一个常用的是 __str__,它决定 print(对象) 时显示什么:

python
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 类,支持开户、存款、取款,并处理非法操作:

python
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(): 忘了 selfTypeError: 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 givenself 由 Python 自动传入,不要手动传
子类 __init__ 忘了 super().__init__(...)不报错但父类属性未初始化需要父类属性时调用 super().__init__()

章末练习

基础

  1. 定义类 Book,有属性 titleauthorprice;创建一本书并打印三个属性。
  2. Book 加方法 info(),返回 "《书名》- 作者" 格式的字符串,调用验证。
  3. Book__str__,让 print(book) 输出 "《Python 入门》- 张三,定价 59 元" 这样的格式。

提高

  1. 定义 Animal 父类(属性 name,方法 speak() 返回 "..."),再定义子类 CatDog,分别重写 speak(),创建对象并输出各自叫声。
  2. 定义 Rectangle 类,属性为宽和高,方法 area() 返回面积;再定义子类 Square,用 super().__init__(side, side) 复用父类初始化,验证边长为 4 的正方形面积为 16。

挑战

  1. 在「银行账户」基础上增加:统计该账户的交易次数属性 count(每次成功存取 +1),并增加方法 show_count() 输出次数。
  2. 思考并回答:下面的需求用类还是函数更合适?说明理由——「一个程序要管理 5 个学生的姓名和成绩,并计算每个学生的平均分」。

章末自测

每题选择一个最佳答案。本书不附答案:完成后交由老师或 AI 老师批改讲解。

  1. 根据模板创建的具体个体叫?
    • A. 类
    • B. 对象
    • C. 函数
    • D. 模块
  2. __init__ 方法的作用是?
    • A. 删除对象
    • B. 创建对象时初始化属性
    • C. 输出对象
    • D. 定义类
  3. 实例方法定义的第一个参数必须是?
    • A. this
    • B. self
    • C. cls
    • D. 没有要求
  4. self.name = name 的作用是?
    • A. 比较两个名字
    • B. 把 name 保存为对象的实例属性
    • C. 定义类属性
    • D. 调用方法
  5. 类属性与实例属性的区别是?
    • A. 类属性所有对象共享
    • B. 实例属性所有对象共享
    • C. 没有区别
    • D. 类属性只能读不能写
  6. class Dog(Animal): 表示?
    • A. Animal 继承 Dog
    • B. Dog 继承 Animal
    • C. Dog 与 Animal 无关
    • D. Dog 复制 Animal
  7. 子类中重写父类方法的含义是?
    • A. 删除父类方法
    • B. 定义同名方法覆盖父类版本
    • C. 复制父类方法
    • D. 报错
  8. super().__init__(name) 的作用是?
    • A. 创建新对象
    • B. 调用父类的初始化方法
    • C. 调用子类方法
    • D. 删除对象
  9. __str__ 方法决定?
    • A. 对象是否可删除
    • B. print(对象) 显示的内容
    • C. 对象的内存地址
    • D. 对象的类型
  10. 下列哪种场景最适合用类? A. 计算 1+1 B. 银行账户(余额 + 存取操作) C. 打印一行文字 D. 读一个文件