Python教程31:类与对象基础
“万物皆对象。”
从今天开始,我们进入Python编程的新境界——面向对象编程(OOP)。这是一种组织代码的强大范式,让程序更贴近真实世界的思维方式。
1. 什么是面向对象编程
编程范式的演进
面向过程编程(Procedural Programming):
- 以函数为中心
- 数据和操作分离
- 适合简单问题
1# 面向过程:管理学生信息
2students = [
3 {"name": "Alice", "age": 20, "grade": 85},
4 {"name": "Bob", "age": 21, "grade": 90}
5]
6
7def calculate_average(students):
8 """计算平均成绩"""
9 total = sum(s["grade"] for s in students)
10 return total / len(students)
11
12# 数据和操作分离
面向对象编程(Object-Oriented Programming, OOP):
- 以对象为中心
- 数据和操作封装在一起
- 更贴近真实世界建模
1# 面向对象:学生类
2class Student:
3 """学生类:数据和行为封装在一起"""
4 def __init__(self, name, age, grade):
5 self.name = name
6 self.age = age
7 self.grade = grade
8
9 def get_info(self):
10 """学生的行为"""
11 return f"{self.name}, {self.age}岁, 成绩{self.grade}"
12
13# 创建对象
14alice = Student("Alice", 20, 85)
15bob = Student("Bob", 21, 90)
OOP的核心概念
类(Class):
- 对象的模板/蓝图
- 定义了对象的属性和方法
- 像是"饼干模具"
对象(Object):
- 类的实例
- 具有实际的数据
- 像是用模具做出的"饼干"
为什么需要OOP:
- 封装:数据和操作组织在一起
- 抽象:隐藏复杂细节,暴露简单接口
- 复用:通过继承重用代码
- 可维护:修改更容易,影响范围更小
- 真实世界建模:程序结构更接近问题域
2. 定义类
基本语法
1class ClassName:
2 """类的文档字符串"""
3
4 # 类体
5 pass
第一个类
1class Dog:
2 """
3 狗类
4 - 定义狗的属性和行为
5 - 这是一个简单的示例类
6 """
7
8 # 类属性(所有实例共享)
9 species = "Canis familiaris" # 物种
10
11 def __init__(self, name, age):
12 """
13 初始化方法(构造函数)
14 - self代表实例本身
15 - name和age是实例属性
16
17 Args:
18 name: 狗的名字
19 age: 狗的年龄
20 """
21 self.name = name # 实例属性
22 self.age = age
23
24 def bark(self):
25 """
26 狗叫的方法
27 - 实例方法的第一个参数必须是self
28 """
29 return f"{self.name} says: Woof!"
30
31 def get_info(self):
32 """获取狗的信息"""
33 return f"{self.name} is {self.age} years old"
34
35# 创建对象(实例化)
36buddy = Dog("Buddy", 3)
37print(buddy.name) # Buddy
38print(buddy.bark()) # Buddy says: Woof!
39print(buddy.get_info()) # Buddy is 3 years old
关键概念
__init__方法:
- 特殊方法(魔术方法),双下划线开头和结尾
- 类的初始化方法(构造函数)
- 创建对象时自动调用
- 用于设置对象的初始状态
self参数:
- 代表实例本身
- 必须是实例方法的第一个参数
- 调用时Python自动传递,不需要手动传
- 可以用其他名字,但约定俗成用self
1# self的作用
2class Example:
3 def __init__(self, value):
4 self.value = value # self.value是实例属性
5
6 def show(self):
7 print(self.value) # 通过self访问实例属性
8
9obj = Example(10)
10obj.show() # 10
11# 实际上调用:Example.show(obj)
3. 类属性 vs 实例属性
类属性
所有实例共享的属性:
1class Circle:
2 """圆类"""
3 # 类属性:所有圆共享同一个π值
4 pi = 3.14159
5 count = 0 # 计数器
6
7 def __init__(self, radius):
8 self.radius = radius # 实例属性:每个圆有自己的半径
9 Circle.count += 1 # 修改类属性
10
11 def area(self):
12 """计算面积"""
13 return Circle.pi * self.radius ** 2
14
15# 使用
16c1 = Circle(5)
17c2 = Circle(10)
18
19# 访问类属性
20print(Circle.pi) # 3.14159
21print(c1.pi) # 3.14159(也可以通过实例访问)
22print(Circle.count) # 2(创建了2个实例)
实例属性
每个实例独有的属性:
1class Person:
2 """人类"""
3 def __init__(self, name, age):
4 # 实例属性:每个人有自己的名字和年龄
5 self.name = name
6 self.age = age
7
8p1 = Person("Alice", 25)
9p2 = Person("Bob", 30)
10
11print(p1.name) # Alice
12print(p2.name) # Bob(不同的实例有不同的属性值)
类属性 vs 实例属性对比
1class Example:
2 class_var = "类属性"
3
4 def __init__(self):
5 self.instance_var = "实例属性"
6
7# 类属性:通过类访问
8print(Example.class_var) # 类属性
9
10# 实例属性:必须通过实例访问
11obj = Example()
12print(obj.instance_var) # 实例属性
13print(obj.class_var) # 也可以访问类属性
14
15# 修改类属性
16Example.class_var = "新值"
17print(obj.class_var) # 新值(所有实例都受影响)
18
19# 实例属性遮蔽类属性
20obj.class_var = "实例的值"
21print(obj.class_var) # 实例的值(只影响这个实例)
22print(Example.class_var) # 新值(类属性未变)
4. 方法
实例方法
最常见的方法类型:
1class BankAccount:
2 """银行账户类"""
3
4 def __init__(self, owner, balance=0):
5 """初始化账户"""
6 self.owner = owner
7 self.balance = balance
8
9 def deposit(self, amount):
10 """
11 存款(实例方法)
12 - 第一个参数是self
13 - 可以访问和修改实例属性
14 """
15 if amount > 0:
16 self.balance += amount
17 return f"存入{amount}元,余额{self.balance}元"
18 return "金额必须大于0"
19
20 def withdraw(self, amount):
21 """取款"""
22 if amount > self.balance:
23 return "余额不足"
24 self.balance -= amount
25 return f"取出{amount}元,余额{self.balance}元"
26
27 def get_balance(self):
28 """查询余额"""
29 return f"{self.owner}的余额:{self.balance}元"
30
31# 使用
32account = BankAccount("张三", 1000)
33print(account.deposit(500)) # 存入500元,余额1500元
34print(account.withdraw(200)) # 取出200元,余额1300元
35print(account.get_balance()) # 张三的余额:1300元
方法的本质
方法是绑定到实例的函数:
1class Example:
2 def method(self, x):
3 return self.value + x
4
5obj = Example()
6obj.value = 10
7
8# 两种调用方式
9print(obj.method(5)) # 15(常用)
10print(Example.method(obj, 5)) # 15(揭示本质)
5. 封装与私有属性
公开属性
默认情况下,所有属性和方法都是公开的:
1class Person:
2 def __init__(self, name):
3 self.name = name # 公开属性
4
5p = Person("Alice")
6print(p.name) # 直接访问
7p.name = "Bob" # 直接修改
私有属性(名称改编)
Python使用__前缀表示私有:
1class BankAccount:
2 """银行账户"""
3
4 def __init__(self, owner, balance):
5 self.owner = owner
6 self.__balance = balance # 私有属性(双下划线开头)
7
8 def deposit(self, amount):
9 """存款"""
10 if amount > 0:
11 self.__balance += amount
12
13 def get_balance(self):
14 """获取余额(提供公开接口)"""
15 return self.__balance
16
17account = BankAccount("张三", 1000)
18
19# 不能直接访问私有属性
20# print(account.__balance) # AttributeError
21
22# 通过公开方法访问
23print(account.get_balance()) # 1000
24
25# 实际上Python做了名称改编(name mangling)
26print(account._BankAccount__balance) # 1000(不推荐这样访问)
Python的私有性:
- Python没有真正的私有
__前缀触发名称改编- 实际变成
_ClassName__attribute - 这是约定,不是强制
受保护属性(单下划线)
1class Example:
2 def __init__(self):
3 self._protected = "受保护" # 单下划线:约定为内部使用
4 self.__private = "私有" # 双下划线:名称改编
5
6obj = Example()
7print(obj._protected) # 可以访问,但不推荐(约定)
命名约定:
- 无下划线:公开
- 单下划线
_:内部使用(约定) - 双下划线
__:私有(名称改编) - 双下划线包围
__name__:魔术方法
6. 对象的创建和销毁
init:初始化
1class Example:
2 def __init__(self, value):
3 """
4 初始化方法
5 - 对象创建后立即调用
6 - 设置对象的初始状态
7 """
8 print("对象正在初始化")
9 self.value = value
10
11obj = Example(10)
12# 输出:对象正在初始化
del:析构
1class Example:
2 def __del__(self):
3 """
4 析构方法
5 - 对象被垃圾回收前调用
6 - 用于清理资源(文件、网络连接等)
7 - 不要依赖它的执行时机
8 """
9 print("对象正在被销毁")
10
11obj = Example()
12del obj # 手动删除
13# 输出:对象正在被销毁
7. 实用示例
学生管理系统
1class Student:
2 """学生类"""
3
4 # 类属性:学生总数
5 total_count = 0
6
7 def __init__(self, name, student_id, grade):
8 """初始化学生"""
9 self.name = name
10 self.student_id = student_id
11 self.grade = grade
12 self.courses = [] # 课程列表
13
14 Student.total_count += 1
15
16 def enroll_course(self, course):
17 """选课"""
18 if course not in self.courses:
19 self.courses.append(course)
20 return f"{self.name}已选课:{course}"
21 return f"{course}已选过"
22
23 def drop_course(self, course):
24 """退课"""
25 if course in self.courses:
26 self.courses.remove(course)
27 return f"{self.name}已退课:{course}"
28 return f"未选{course}"
29
30 def get_info(self):
31 """获取学生信息"""
32 courses_str = ", ".join(self.courses) if self.courses else "无"
33 return f"""
34学生信息:
35姓名:{self.name}
36学号:{self.student_id}
37年级:{self.grade}
38已选课程:{courses_str}
39"""
40
41 @classmethod
42 def get_total_count(cls):
43 """获取学生总数(类方法)"""
44 return f"学生总数:{cls.total_count}"
45
46# 使用
47student1 = Student("张三", "S001", 1)
48student2 = Student("李四", "S002", 2)
49
50print(student1.enroll_course("Python编程"))
51print(student1.enroll_course("数据结构"))
52print(student1.get_info())
53
54print(Student.get_total_count()) # 学生总数:2
8. 与Golang的对比
Golang也支持面向对象,但方式不同:
1// Golang:使用结构体
2type Dog struct {
3 Name string
4 Age int
5}
6
7// 方法通过接收者定义
8func (d *Dog) Bark() string {
9 return d.Name + " says: Woof!"
10}
11
12// 使用
13dog := Dog{Name: "Buddy", Age: 3}
14fmt.Println(dog.Bark())
对比:
- Python:以类为中心,显式self
- Go:以结构体为中心,方法接收者
- Python:动态类型,运行时检查
- Go:静态类型,编译时检查
9. 小结
今天我们学习了OOP基础:
- 类与对象:模板与实例
- 定义类:class关键字
- init:初始化方法
- self:实例引用
- 属性:类属性vs实例属性
- 方法:实例方法
- 封装:公开、私有、受保护
- 命名约定:
_和__的含义
这是面向对象编程的基础,后续我们将学习继承、多态等高级特性。
练习题:
- 创建一个
Rectangle类,包含长和宽属性,以及计算面积和周长的方法 - 创建一个
Book类,实现图书管理的基本功能 - 对比类属性和实例属性的使用场景
本文代码示例:
关注公众号:极客老墨
更多 AI 应用开发、工程实践和效率工具分享,欢迎扫码关注。
