Python: 类与对象

前几课我们用函数组织代码,这是"面向过程"的方式——关注"做什么"。而面向对象编程(OOP)关注的是"谁来做"——把数据和操作数据的方法打包成一个对象。Python 一切皆对象,理解 OOP 是进阶的关键一步。


1. 什么是类和对象

(class)是模板,对象(object)是根据模板创建的具体实例。

PYTHON
# 定义一个"狗"的类——就是模板
class Dog:
    pass

# 根据模板创建具体的"狗"对象
my_dog = Dog()
print(type(my_dog))         # <class '__main__.Dog'>
print(my_dog)               # <__main__.Dog object at 0x...>

就像"狗"这个品种是一个概念(类),你家养的那条叫旺财的狗(对象)是具体的实例。一个类可以创建无数个对象。

💡 现实类比: 类是"设计图纸",对象是"按图纸造出来的实物"。一张图纸可以造很多个实物,每个实物有自己的状态(比如不同的狗有不同的名字和年龄)。



2. __init__:构造方法

当创建对象时,__init__ 方法会自动被调用,用来初始化对象的属性:

PYTHON
class Dog:
    """狗类"""
    def __init__(self, name, age):
        self.name = name    # 实例属性
        self.age = age

# 创建对象时传入参数
dog1 = Dog("旺财", 3)
dog2 = Dog("小白", 1)

print(dog1.name)            # 旺财
print(dog2.name)            # 小白
print(dog1.age)             # 3

❗注意: __init__ 不是构造函数——对象已经创建好了才调用它。真正的构造函数是 __new__,但日常几乎不需要动它。__init__ 的第一个参数永远是 self,代表当前对象实例。

▶ 示例:定义学生类(难度⭐)

PYTHON
class Student:
    """学生类"""
    def __init__(self, name, student_id, score):
        self.name = name
        self.student_id = student_id
        self.score = score

    def introduce(self):
        """自我介绍"""
        return f"我叫{self.name},学号{self.student_id},本次考试{self.score}分。"
    
    def is_pass(self):
        """判断是否及格"""
        return self.score >= 60

# 创建学生对象
s1 = Student("Alice", "2024001", 85)
s2 = Student("Bob", "2024002", 45)

print(s1.introduce())       # 我叫Alice,学号2024001,本次考试85分。
print(s2.introduce())       # 我叫Bob,学号2024002,本次考试45分。
print(f"Alice及格吗?{s1.is_pass()}")   # True
print(f"Bob及格吗?{s2.is_pass()}")   # False
▶ 试一试

输出:

TEXT 📖 仅展示
# 函数定义成功


3. 方法:对象的行为

类中定义的函数叫方法,第一个参数永远是 self——代表调用这个方法的对象本身。

PYTHON
class Calculator:
    """简单计算器"""
    def __init__(self):
        self.result = 0
    
    def add(self, value):
        self.result += value
        return self
    
    def subtract(self, value):
        self.result -= value
        return self
    
    def show(self):
        return self.result

calc = Calculator()
calc.add(10)
calc.subtract(3)
print(calc.show())                  # 7

# 方法链式调用——因为每个方法都返回 self
result = Calculator().add(10).subtract(3).add(5).show()
print(result)                       # 12
💡 链式调用的技巧: 方法返回 self 就可以连续调用了。很多 Python 库(如 pandas)大量使用这个模式。



4. 实例属性 vs 类属性

属性可以定义在实例上(每个对象独有),也可以定义在类上(所有对象共享):

PYTHON
class Student:
    # 类属性——所有学生共享
    school = "第一中学"
    total_count = 0
    
    def __init__(self, name):
        # 实例属性——每个学生独有
        self.name = name
        Student.total_count += 1

s1 = Student("Alice")
s2 = Student("Bob")

# 类属性通过类名访问
print(Student.school)       # 第一中学
print(Student.total_count)  # 2

# 也可以通过实例访问(如果实例没有同名属性)
print(s1.school)            # 第一中学
print(s2.school)            # 第一中学

# 修改类属性会影响所有实例
Student.school = "第二中学"
print(s1.school)            # 第二中学

▶ 示例:银行账户(难度⭐⭐)

PYTHON
class BankAccount:
    """银行账户"""
    bank_name = "Python银行"          # 类属性
    interest_rate = 0.003             # 年利率 0.3%
    
    def __init__(self, owner, balance=0):
        self.owner = owner            # 实例属性
        self.balance = balance        # 实例属性
    
    def deposit(self, amount):
        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 yearly_interest(self):
        """计算年利息"""
        interest = self.balance * BankAccount.interest_rate
        return f"年利息:{interest:.2f}元"

acc1 = BankAccount("Alice", 10000)
acc2 = BankAccount("Bob", 5000)

print(acc1.deposit(5000))           # 存入5000元,余额15000元
print(acc2.withdraw(2000))          # 取出2000元,余额3000元
print(acc1.yearly_interest())       # 年利息:4.50元

# 所有账户共享利率
print(acc1.interest_rate)           # 0.003
print(acc2.interest_rate)           # 0.003
▶ 试一试

输出:

TEXT 📖 仅展示
# 函数定义成功


▶ 示例:学生成绩管理类(难度⭐⭐)

PYTHON
class Student:
    """学生类——带成绩管理方法"""
    school = "编程学院"
    total = 0

    def __init__(self, name, student_id):
        self.name = name
        self.student_id = student_id
        self.scores = {}
        Student.total += 1

    def add_score(self, subject, score):
        """添加一门课的成绩"""
        self.scores[subject] = score

    def average(self):
        """计算平均分"""
        if not self.scores:
            return 0
        return sum(self.scores.values()) / len(self.scores)

    def report(self):
        """生成成绩报告"""
        lines = [f"学生:{self.name}({self.student_id})"]
        for subj, sc in self.scores.items():
            status = "及格" if sc >= 60 else "不及格"
            lines.append(f"  {subj}:{sc}分({status})")
        lines.append(f"  平均分:{self.average():.1f}")
        return "\n".join(lines)

s1 = Student("Alice", "001")
s1.add_score("语文", 85)
s1.add_score("数学", 72)
s1.add_score("英语", 90)

s2 = Student("Bob", "002")
s2.add_score("语文", 55)
s2.add_score("数学", 48)

print(s1.report())
print()
print(s2.report())
print(f"\n全校学生数:{Student.total}")
▶ 试一试

输出:

TEXT 📖 仅展示
学生:Alice(001)
  语文:85分(及格)
  数学:72分(及格)
  英语:90分(及格)
  平均分:82.3

学生:Bob(002)
  语文:55分(不及格)
  数学:48分(不及格)
  平均分:51.5

全校学生数:2


5. 常见应用场景


❓ 常见问题

Q 方法和函数有什么区别?
A 方法就是在类中定义的函数,第一个参数是 self。函数可以独立存在,方法必须通过对象或类调用。本质上方法也是函数,只是 Python 自动把调用者作为第一个参数传进去。
Q 什么时候用类,什么时候用函数?
A 如果你需要维护状态(数据),用类——比如银行账户要记住余额。如果你只是做一次计算(输入→处理→输出),用函数——比如温度转换。一个简单的经验法则:如果只需要 1-2 个函数,用函数就够了;如果需要多个相关函数共享同一份数据,用类。

📖 小节


📝 作业

  1. 基础题(难度⭐):定义一个 Car 类,有 brandcolorspeed 属性,有 accelerate(value) 加速方法和 show_speed() 显示速度的方法。

  2. 进阶题(难度⭐⭐):定义一个 Student 类,用类属性统计学生总数,用实例属性记录每个学生的姓名和成绩。实现 get_grade() 方法返回等级(ABCD)。

  3. 挑战题(难度⭐⭐⭐):定义一个 Library 类和 Book 类。Book 有标题、作者、是否借出状态。Libraryadd_book(book)borrow(title)return_book(title)show_books() 四个方法。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏