Python面向对象入门:类与对象的基础代码示例

沈知远
沈知远
发布时间:2026-10-10| 3人浏览过
原创

面向对象编程(OOP)的核心在于把“数据”与“对数据的操作”打包成一个独立的单元。在 Python 中,理解面向对象只需要搞清楚两个基本概念:类(Class)是用于生成对象的模板,而对象(Object)是根据模板生产出来的具体实例。本文将通过可运行的精简代码和直观图解,分步解析类的定义、实例化、__init__ 构造方法以及 self 参数的作用机制。

一、核心认知:什么是“类”与“对象”

初学者在接触面向对象时,常常困惑于它与普通函数有什么区别。面向过程的代码习惯于将数据保存在零散的字典或列表中,再写一堆函数去接收并修改这些变量。当项目规模扩大时,数据结构一旦改变,所有相关的函数都需要逐个调整,代码维护成本极高。

面向对象提供了一种组织代码的新思路:它让你把事物的状态特征(属性)和行为动作(方法)整合在一起。

  • 类(Class):相当于一张建筑蓝图,或者做月饼的模具。它规定了未来生产出来的物体应该长什么样、具备哪些功能,但蓝图本身并不占用实际地皮。
  • 对象(Object / Instance):则是根据蓝图真正建造出来的房子,或者从模具里倒出来的月饼。你可以基于同一张蓝图建造多座房子,它们结构一致,但门牌号、室内装修和住户各不相同。
Python面向对象入门:类与对象的基础代码示例
图 1 架构示意:类作为定义规范的模板,能够实例化出状态互相独立的对象。

二、基础语法:如何定义类与创建对象

在 Python 中,通过 class 关键字来声明一个类。根据 PEP 8 命名规范,类名一般采用大驼峰命名法(PascalCase),即每个单词的首字母大写,例如 StudentCourse。

下面是一个极简示例,展示如何定义一个空类并基于它创建对象:

# 1. 定义一个最简单的类
class Dog:
    pass  # pass 是占位语句,表示暂无具体代码

# 2. 实例化对象(通过 类名() 调用)
my_dog = Dog()

# 3. 打印对象的类型和内存地址
print(type(my_dog))
print(my_dog)
示例运行输出
<class '__main__.Dog'>
<__main__.Dog object at 0x7fa28c11e350>

从输出结果可以看到,my_dog 是一个类型为 Dog 的对象,后面的十六进制字符串展示了它在内存中的存储地址。

三、核心机制:__init__ 构造方法与 self

光有一个空对象并没有实际价值。通常我们希望在创建对象的同时,把它的初始属性(比如名字、年龄)一起绑定好。在 Python 中,这是通过 __init__ 初始化方法来实现的。

Python面向对象入门:类与对象的基础代码示例
图 2 执行流程:通过三个连贯步骤展示从调用类构造到最终属性赋值的底层过程。

1. 理解 __init__ 方法

双下划线开头和结尾的方法在 Python 中被称为“魔法方法”或“特殊方法”。__init__ 是最常用的魔法方法,它在对象被创建之后立即被自动调用。不需要你手动去执行 p.__init__(),当你写出 Dog("小白") 时,Python 会在后台帮你完成这次调用。

2. 理解 self 的含义

在类的方法定义中,第一个参数总是 self。很多初学者在这里产生疑问:调用时明明没有传它,它到底是干什么的?

self 代表的其实就是当前正在被操作的具体对象本身。类是一个通用模板,当有三个不同的狗对象同时想要调用“叫一声”的方法时,计算机必须搞清楚到底是哪一只狗在叫。self 就像现实生活中的第一人称代词“我”,在类的代码中,self.name 指的就是“我自己的名字”。

注意事项:虽然 Python 语法允许你将 self 命名为其他标识符(如 this 或 me),但强烈建议严格使用 self。这是全体 Python 开发者的共识规范,替换它会严重降低代码的可读性。

四、完整实战代码:银行账户管理器

我们来看一个贴近真实应用场景的完整示例:使用面向对象的方式编写一个银行账户管理器,让读者直观感受属性读写与方法调用的全过程。

# 完整可运行代码示例:BankAccount 类
class BankAccount:
    """简易银行账户管理类"""
    
    def __init__(self, owner, initial_balance=0.0):
        # 实例属性:归属于每个独立的账户对象
        self.owner = owner
        self.balance = float(initial_balance)

    def deposit(self, amount):
        """存钱方法"""
        if amount > 0:
            self.balance += amount
            print(f"[{self.owner}] 成功存入: {amount} 元,当前余额: {self.balance} 元")
        else:
            print(f"[{self.owner}] 存入金额必须大于 0!")

    def withdraw(self, amount):
        """取钱方法"""
        if amount <= 0:
            print(f"[{self.owner}] 取款金额必须大于 0!")
        elif amount > self.balance:
            print(f"[{self.owner}] 余额不足!当前可用余额: {self.balance} 元,尝试取出: {amount} 元")
        else:
            self.balance -= amount
            print(f"[{self.owner}] 成功取出: {amount} 元,当前余额: {self.balance} 元")

    def check_balance(self):
        """查询余额方法"""
        print(f"[{self.owner}] 账户最终余额: {self.balance} 元")


# ---------------- 测试运行 ----------------
# 创建第一个独立账户:Alice
account_a = BankAccount(owner="Alice", initial_balance=1000.0)

# 创建第二个独立账户:Bob
account_b = BankAccount(owner="Bob", initial_balance=200.0)

# 针对不同对象进行独立操作
account_a.deposit(500)       # Alice 存入 500
account_a.withdraw(200)      # Alice 取出 200

account_b.withdraw(300)      # Bob 尝试取出 300(预期提示余额不足)
account_b.deposit(100)       # Bob 存入 100

# 查看两个对象的最终状态
account_a.check_balance()
account_b.check_balance()
示例运行输出
[Alice] 成功存入: 500 元,当前余额: 1500.0 元
[Alice] 成功取出: 200 元,当前余额: 1300.0 元
[Bob] 余额不足!当前可用余额: 200.0 元,尝试取出: 300 元
[Bob] 成功存入: 100 元,当前余额: 300.0 元
[Alice] 账户最终余额: 1300.0 元
[Bob] 账户最终余额: 300.0 元

通过上面的输出结果可以清晰看到:虽然 account_a 和 account_b 执行的是同一套 deposit 与 withdraw 逻辑,但它们内部的 balance 数值彼此完全隔离,互不干扰。这就是对象状态独立性的体现。

五、进阶对比:实例属性与类属性的区别

在初学阶段,另一个容易被混淆的概念是“类属性”与“实例属性”。

  • 实例属性(Instance Attribute):定义在 __init__ 内部,带 self. 前缀。每个对象独享一份,修改一个对象的实例属性不会影响其他对象。
  • 类属性(Class Attribute):直接定义在类体内部、方法之外。它是所有由该类创建出来的对象共同共享的公共变量。
Python面向对象入门:类与对象的基础代码示例
图 3 细节对比:直观展示类属性的共享内存特性与实例属性的独立封闭特性。

通过以下代码可以清晰验证两者的差异:

class Employee:
    # 类属性(所有员工都属于同一家公司)
    company_name = "未来科技"

    def __init__(self, name):
        # 实例属性(每个员工有不同的姓名)
        self.name = name

# 创建两名员工
e1 = Employee("王五")
e2 = Employee("赵六")

# 1. 访问类属性(可以直接用 类名.属性名 访问,也可以用 对象.属性名 访问)
print(Employee.company_name)  # 输出: 未来科技
print(e1.company_name)        # 输出: 未来科技

# 2. 修改类属性(必须使用 类名.属性名 进行修改)
Employee.company_name = "创新未来"
print(e1.company_name)        # 输出: 创新未来
print(e2.company_name)        # 输出: 创新未来(全部联动变更)

# 3. 常见陷阱:如果通过实例对象赋值类属性
e1.company_name = "临时子公司"  # 这不会修改类属性,而是给 e1 悄悄新增了一个名为 company_name 的实例属性!
print(e1.company_name)          # 输出: 临时子公司(优先读取实例自身的属性)
print(e2.company_name)          # 输出: 创新未来(其他对象依旧读取原类属性)

六、初学者常见报错与排查清单

在编写类和对象代码时,有两类报错最常出现,遇到时可根据以下规律快速排查定位:

1. TypeError: __init__() takes X positional arguments but Y were given

报错原因:传递的参数个数与 __init__ 定义的参数不一致。请牢记:调用时传入的参数是自动匹配给 self 后面的参数的。如果你写了 def __init__(self, name),调用时却写了 Person()(没有传参数),就会报缺少 1 个位置参数。

2. TypeError: my_method() takes 0 positional arguments but 1 was given

报错原因:在类中定义常规方法时漏写了 self。例如定义了 def speak(): pass,而在调用 obj.speak() 时,Python 会自动把 obj 作为第一个参数硬塞进去,导致参数多出了一个。只要在方法声明处补上 self 即可修复。

七、总结:面向对象入门要点速查

Python面向对象入门:类与对象的基础代码示例
图 4 总结导图:四个基础要素协同构成 Python 面向对象编程的核心基石。

掌握类与对象是后续深入学习继承(Inheritance)、封装(Encapsulation)以及多态(Polymorphism)的前提。在日常练习中,建议先通过具体的现实事物(例如汽车、员工、购物车)尝试写出简单的类结构,观察多个对象属性的变化,从而形成直观的代码感知。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。