1_10_类#
作者: ZhouLong
创建日期: 2026 年 01 月 20 日
版本: 1.0
浏览量:
1. 类与面向对象编程概念#
1.1 什么是面向对象编程#
面向对象编程,又称为OOP,是一种编程范式,它将数据和操作数据的方法组合成"对象",通过对象之间的交互来解决问题。
三大核心特性:
封装:将数据和方法包装在类中,隐藏内部实现细节
继承:子类可以继承父类的属性和方法,实现代码复用
多态:不同类的对象可以对同一消息做出不同响应
# 现实世界中的对象类比
# 类:汽车设计图
# 对象:根据设计图制造的具体汽车
# 属性:颜色、品牌、速度
# 方法:加速、刹车、转向
1.2 为什么使用类#
代码复用:通过继承减少重复代码
模块化:将复杂系统分解为独立对象
维护性:修改一个类不会影响其他部分
现实映射:更容易模拟现实世界问题
2. 类的基本结构#
2.1 定义类#
类的定义是面向对象编程的基础,核心要点:
类定义语法:使用
class关键字,类名采用大驼峰命名法初始化方法:
__init__是特殊的构造函数,在创建对象时自动调用实例属性:通过
self.属性名定义,每个对象拥有独立副本实例方法:定义在类中的函数,第一个参数通常是
self,用于访问实例属性
关键概念:
self参数代表当前对象实例,在方法内部访问属性时必须使用类定义后需要通过实例化来创建具体对象
每个对象都有自己的属性值,互不影响
# 定义一个简单的类
class Person:
"""这是一个人类"""
def __init__(self, name, age):
"""初始化方法(构造函数)"""
self.name = name # 实例属性
self.age = age # 实例属性
def introduce(self):
"""实例方法"""
return f"我叫{self.name},今年{self.age}岁"
# 创建对象(实例化)。类在实例化时候会得到一个对象
person1 = Person("张三", 25) #第一个对象(实例)
person2 = Person("李四", 30) #第二个对象(实例)
print(person1.introduce()) # 输出:我叫张三,今年25岁
print(person2.introduce()) # 输出:我叫李四,今年30岁
2.2 __init__方法#
这是类的特殊方法,用于初始化新创建的对象
第一个参数必须是
self,代表对象本身这个方法在创建对象时自动调用
class Student:
def __init__(self, name, student_id):
print("正在创建学生对象...") #初始化时候会被调用
self.name = name
self.student_id = student_id
self.grades = [] # 初始化空列表
# 实例化时会自动调用__init__
student = Student("王五", "2023001")
print(f"姓名:{student.name},学号:{student.student_id}")
运行结果
正在创建学生对象...
姓名:王五,学号:2023001
3. 类的三大要素#
3.1 属性#
类中属性分为两种,区别如下:
类属性:
定义在类内部、方法外部
所有实例对象共享同一份数据
可通过
类名.属性名或self.__class__.属性名访问
实例属性:
定义在
__init__方法中,使用self.属性名绑定每个实例拥有独立副本,互不影响
只能通过实例对象访问
重要特性:
类属性通常用于存储类的共有特征(如常数)
实例属性存储对象的个体特征
修改实例属性只影响当前对象,修改类属性会影响所有实例
class Circle:
# 类属性 - 所有实例共享
pi = 3.14159
def __init__(self, radius):
# 实例属性 - 每个实例独有
self.radius = radius
def area(self):
# 访问类属性:类名.类属性 或 self.__class__.类属性
return self.__class__.pi * self.radius ** 2
# 创建实例
circle1 = Circle(5)
circle2 = Circle(10)
print("圆周率:", Circle.pi) # 通过类名访问
print("圆1面积:", circle1.area())
print("圆2面积:", circle2.area())
# 修改实例属性
circle1.radius = 7
print("修改后圆1面积:", circle1.area())
运行结果
圆周率: 3.14159
圆1面积: 78.53975
圆2面积: 314.159
修改后圆1面积: 153.93791
3.2 方法#
类中的方法主要有三种类型,区别如下:
实例方法:
第一个参数必须是
self,代表当前实例可以访问和修改实例属性及类属性
只能通过实例对象调用
类方法:
使用
@classmethod装饰器,第一个参数必须是cls,代表当前类主要用于操作类属性或执行与类相关的操作
可通过类名或实例调用
静态方法:
使用
@staticmethod装饰器,不需要self或cls参数类似于普通函数,但逻辑上属于类
不能访问实例属性或类属性,仅提供工具功能
核心区别:
实例方法操作对象数据,类方法操作类数据,静态方法执行独立功能
选择依据:是否需要访问实例属性(
self)、类属性(cls)
class Calculator:
# 类属性
operation_count = 0
def __init__(self, brand):
self.brand = brand
self.memory = 0
# 实例方法 - 第一个参数必须是self
def add(self, a, b):
self.__class__.operation_count += 1
self.memory = a + b
return self.memory
# 类方法 - 第一个参数必须是cls,使用@classmethod装饰器
@classmethod
def get_operation_count(cls):
return f"总操作次数: {cls.operation_count}"
# 静态方法 - 不需要self或cls参数,使用@staticmethod装饰器
@staticmethod
def help():
return "这是一个计算器类,支持加减乘除运算"
# 使用不同方法
calc = Calculator("卡西欧")
# 调用实例方法
result = calc.add(10, 20)
print(f"计算结果: {result}")
# 调用类方法
print(Calculator.get_operation_count())
# 调用静态方法
print(Calculator.help())
print(calc.help()) # 也可以通过实例调用
运行结果
计算结果: 30
总操作次数: 1
这是一个计算器类,支持加减乘除运算
这是一个计算器类,支持加减乘除运算
3.3 访问控制#
Python通过命名约定而非强制机制实现访问控制,分为三个级别:
公开属性:普通命名,如
self.owner可在任何地方直接访问和修改
受保护属性:单下划线开头,如
self._password约定上的"内部使用"属性,外部可访问但不推荐
主要作为提示,不阻止访问
私有属性:双下划线开头,如
self.__balance会触发名称修饰(name mangling),实际变为
_类名__属性名从外部无法直接访问,但可通过特殊方式访问(不推荐)
最佳实践:
使用公有方法(getter/setter)控制对私有属性的访问
私有属性保护数据完整性,防止外部随意修改
受保护属性常用于子类访问的父类属性
class BankAccount:
def __init__(self, owner, initial_balance):
self.owner = owner # 公开属性
self._password = "123456" # 受保护属性(约定)
self.__balance = initial_balance # 私有属性
def deposit(self, amount):
"""存款"""
if amount > 0:
self.__balance += amount
return True
return False
def withdraw(self, amount):
"""取款"""
if 0 < amount <= self.__balance:
self.__balance -= amount
return amount
return 0
# 获取私有属性的公开方法
def get_balance(self):
return self.__balance
# 设置私有属性的公开方法
def set_balance(self, new_balance):
if new_balance >= 0:
self.__balance = new_balance
return True
return False
# 创建账户
account = BankAccount("张三", 1000)
# 访问公开属性
print(f"账户所有人: {account.owner}")
# 访问受保护属性(不推荐)
print(f"密码: {account._password}")
# 直接访问私有属性会出错
# print(account.__balance) # 报错: AttributeError
# 通过方法访问私有属性
print(f"余额: {account.get_balance()}")
# 存款和取款
account.deposit(500)
print(f"存款后余额: {account.get_balance()}")
withdrawn = account.withdraw(300)
print(f"取款: {withdrawn}, 余额: {account.get_balance()}")
运行结果
账户所有人: 张三
密码: 123456
余额: 1000
存款后余额: 1500
取款: 300, 余额: 1200
4. 继承#
4.1 基本继承#
继承是面向对象的核心特性,允许子类获取父类的功能:
继承语法:子类括号中指定父类,如
class Dog(Animal)继承内容:子类自动获得父类的所有方法和属性(私有成员除外)
初始化父类:使用
super().__init__()调用父类构造函数
关键机制:
方法重写:子类定义同名方法可覆盖父类实现
扩展功能:子类可添加新属性和方法
super()函数:用于调用父类的方法,避免硬编码父类名
继承优势:
代码复用,避免重复
建立类之间的层次关系
支持多态性设计
# 父类(基类)
class Animal:
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
return f"{self.name}正在吃东西"
def sleep(self):
return f"{self.name}正在睡觉"
# 子类(派生类)
class Dog(Animal):
def __init__(self, name, age, breed):
# 调用父类的__init__方法
super().__init__(name, age)
# 子类特有的属性
self.breed = breed
# 子类特有的方法
def bark(self):
return f"{self.name}在汪汪叫"
# 重写父类方法
def eat(self):
return f"{self.name}({self.breed}品种)正在吃狗粮"
# 创建子类实例
dog = Dog("旺财", 3, "金毛")
# 调用继承的方法
print(dog.eat()) # 重写后的方法
print(dog.sleep()) # 继承的方法
print(dog.bark()) # 子类特有的方法
print(f"品种: {dog.breed}")
运行结果
旺财(金毛品种)正在吃狗粮
旺财正在睡觉
旺财在汪汪叫
品种: 金毛
4.2 多重继承#
多重继承允许一个类继承多个父类,需要注意:
语法:在类定义中括号内用逗号分隔多个父类
继承内容:子类获得所有父类的属性和方法
方法解析顺序:Python使用MRO算法确定方法查找顺序
MRO(方法解析顺序)特点:
使用C3线性化算法,遵循
__mro__属性顺序查找顺序:从左到右,深度优先(但避免重复)
可通过
类名.__mro__查看具体顺序
注意事项:
避免复杂的多重继承,防止"菱形继承"问题
当多个父类有同名方法时,按MRO顺序调用第一个找到的方法
设计时应优先考虑组合而非多重继承
class Flyable:
def fly(self):
return "我能飞"
class Swimmable:
def swim(self):
return "我能游泳"
class Duck(Flyable, Swimmable):
def __init__(self, name):
self.name = name
def quack(self):
return f"{self.name}在嘎嘎叫"
# 创建多重继承的实例
duck = Duck("唐老鸭")
print(duck.quack())
print(duck.fly())
print(duck.swim())
# 查看方法解析顺序
print("方法解析顺序:", Duck.__mro__)
运行结果
唐老鸭在嘎嘎叫
我能飞
我能游泳
方法解析顺序: (<class '__main__.Duck'>, <class '__main__.Flyable'>, <class '__main__.Swimmable'>, <class 'object'>)
5. 特殊方法(魔术方法)#
特殊方法(魔术方法)赋予类自定义行为的能力,常见类型包括:
对象表示:
__str__:用户友好字符串,用于print()和str()__repr__:开发者准确表示,用于交互式环境和repr()
运算符重载:
__add__:实现+运算__eq__:实现==比较__len__:实现len()函数支持
其他常用方法:
__init__:对象初始化__del__:对象销毁前清理
核心要点:
特殊方法在特定操作时由Python自动调用
允许自定义对象的内置行为
实现这些方法可使类更自然、易用
class Book:
def __init__(self, title, author, pages):
self.title = title
self.author = author
self.pages = pages
# 字符串表示方法
def __str__(self):
return f"《{self.title}》 - {self.author}"
def __repr__(self):
return f"Book('{self.title}', '{self.author}', {self.pages})"
# 长度
def __len__(self):
return self.pages
# 比较方法
def __eq__(self, other):
if isinstance(other, Book):
return self.title == other.title and self.author == other.author
return False
# 加法运算
def __add__(self, other):
if isinstance(other, Book):
# 创建一个组合书籍
new_title = f"{self.title} & {other.title}"
new_author = f"{self.author} 和 {other.author}"
new_pages = self.pages + other.pages
return Book(new_title, new_author, new_pages)
raise TypeError("只能与Book实例相加")
# 使用特殊方法
book1 = Book("Python编程", "张三", 300)
book2 = Book("算法导论", "李四", 500)
print(str(book1)) # 调用__str__
print(repr(book1)) # 调用__repr__
print(f"页数: {len(book1)}") # 调用__len__
# 比较书籍
book3 = Book("Python编程", "张三", 350)
print(f"book1 == book3: {book1 == book3}")
# 书籍相加
combined_book = book1 + book2
print(f"合并后的书籍: {combined_book}")
print(f"总页数: {len(combined_book)}")
运行结果
《Python编程》 - 张三
Book('Python编程', '张三', 300)
页数: 300
book1 == book3: True
合并后的书籍: 《Python编程 & 算法导论》 - 张三 和 李四
总页数: 800
6. 属性装饰器#
属性装饰器提供了更优雅的属性访问控制方式:
@property:将方法转换为只读属性
@属性名.setter:定义属性的设置逻辑
@属性名.deleter:定义属性的删除逻辑
核心优势:
保持简单属性访问语法(
obj.property)封装内部实现细节,外部无需知道属性存储方式
可在getter/setter中添加验证、计算等逻辑
典型应用场景:
需要验证或转换输入值时
创建计算属性(根据其他属性动态计算)
实现向后兼容的API更改
设计要点:
只读属性只需定义
@property可写属性需同时定义
@property和@setter保持setter的验证逻辑,确保数据完整性
class Temperature:
def __init__(self, celsius):
self._celsius = celsius
@property
def celsius(self):
"""获取摄氏温度"""
return self._celsius
@celsius.setter
def celsius(self, value):
"""设置摄氏温度"""
if value < -273.15:
raise ValueError("温度不能低于绝对零度")
self._celsius = value
@property
def fahrenheit(self):
"""华氏温度(只读属性)"""
return self._celsius * 9/5 + 32
@property
def kelvin(self):
"""开尔文温度(只读属性)"""
return self._celsius + 273.15
# 使用属性装饰器
temp = Temperature(25)
print(f"摄氏温度: {temp.celsius}°C")
print(f"华氏温度: {temp.fahrenheit}°F")
print(f"开尔文温度: {temp.kelvin}K")
# 修改温度
temp.celsius = 30
print(f"修改后华氏温度: {temp.fahrenheit}°F")
# 尝试设置无效温度
try:
temp.celsius = -300
except ValueError as e:
print(f"错误: {e}")
运行结果
《Python编程》 - 张三
Book('Python编程', '张三', 300)
页数: 300
book1 == book3: True
合并后的书籍: 《Python编程 & 算法导论》 - 张三 和 李四
总页数: 800
7. 实践案例#
7.1 学生管理系统#
本学生管理系统示例演示了如何使用面向对象编程解决实际问题。系统包含两个核心类:Student类用于表示单个学生信息,包括学号、姓名和各科成绩;StudentManager类作为管理器,负责学生对象的存储和批量操作。通过这个案例,展示了如何设计类结构、封装数据、定义方法,并将多个类组合协作来完成完整功能。
class Student:
def __init__(self, student_id, name):
self.student_id = student_id
self.name = name
self.scores = {}
def add_score(self, subject, score):
"""添加成绩"""
if 0 <= score <= 100:
self.scores[subject] = score
return True
return False
def get_average(self):
"""计算平均分"""
if not self.scores:
return 0
return sum(self.scores.values()) / len(self.scores)
def __str__(self):
avg = self.get_average()
return f"学号: {self.student_id}, 姓名: {self.name}, 平均分: {avg:.1f}"
class StudentManager:
def __init__(self):
self.students = {}
def add_student(self, student_id, name):
"""添加学生"""
if student_id not in self.students:
self.students[student_id] = Student(student_id, name)
return True
return False
def find_student(self, student_id):
"""查找学生"""
return self.students.get(student_id)
def get_top_student(self):
"""获取成绩最好的学生"""
if not self.students:
return None
return max(self.students.values(), key=lambda s: s.get_average())
def show_all_students(self):
"""显示所有学生"""
print("=" * 40)
print("学生列表:")
print("=" * 40)
for student in self.students.values():
print(student)
print("=" * 40)
# 使用学生管理系统
manager = StudentManager()
# 添加学生
manager.add_student("2023001", "张三")
manager.add_student("2023002", "李四")
manager.add_student("2023003", "王五")
# 添加成绩
student1 = manager.find_student("2023001")
if student1:
student1.add_score("数学", 85)
student1.add_score("英语", 92)
student1.add_score("物理", 78)
student2 = manager.find_student("2023002")
if student2:
student2.add_score("数学", 90)
student2.add_score("英语", 88)
student2.add_score("物理", 95)
# 显示所有学生
manager.show_all_students()
# 找到最佳学生
top_student = manager.get_top_student()
if top_student:
print(f"\n最佳学生: {top_student.name}, 平均分: {top_student.get_average():.1f}")
运行结果
========================================
学生列表:
========================================
学号: 2023001, 姓名: 张三, 平均分: 85.0
学号: 2023002, 姓名: 李四, 平均分: 91.0
学号: 2023003, 姓名: 王五, 平均分: 0.0
========================================
最佳学生: 李四, 平均分: 91.0
7.2 几何图形类#
这是一个面向对象编程的综合示例,展示了如何定义图形类的层次结构,其中包含一个抽象基类和多个具体子类,分别实现不同几何图形的面积和周长计算。
import math
class Shape:
"""图形基类"""
def area(self):
"""计算面积"""
raise NotImplementedError("子类必须实现此方法")
def perimeter(self):
"""计算周长"""
raise NotImplementedError("子类必须实现此方法")
def __str__(self):
return f"{self.__class__.__name__} - 面积: {self.area():.2f}, 周长: {self.perimeter():.2f}"
class Rectangle(Shape):
"""矩形类"""
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
class Circle(Shape):
"""圆形类"""
def __init__(self, radius):
self.radius = radius
def area(self):
return math.pi * self.radius ** 2
def perimeter(self):
return 2 * math.pi * self.radius
class Triangle(Shape):
"""三角形类"""
def __init__(self, a, b, c):
# 验证是否可以构成三角形
if a + b > c and a + c > b and b + c > a:
self.a = a
self.b = b
self.c = c
else:
raise ValueError("这三条边不能构成三角形")
def area(self):
# 使用海伦公式
s = self.perimeter() / 2
return math.sqrt(s * (s - self.a) * (s - self.b) * (s - self.c))
def perimeter(self):
return self.a + self.b + self.c
# 测试各种图形
shapes = [
Rectangle(5, 3),
Circle(4),
Triangle(3, 4, 5)
]
print("各种图形的面积和周长:")
print("=" * 50)
for shape in shapes:
print(shape)
print("=" * 50)
运行结果
各种图形的面积和周长:
==================================================
Rectangle - 面积: 15.00, 周长: 16.00
Circle - 面积: 50.27, 周长: 25.13
Triangle - 面积: 6.00, 周长: 12.00
==================================================
8. 总结与最佳实践#
8.1 面向对象设计原则#
单一职责原则:一个类只负责一个功能领域
开放封闭原则:对扩展开放,对修改封闭
里氏替换原则:子类必须能够替换父类
接口隔离原则:使用多个专门接口比使用单一接口更好
依赖倒置原则:依赖抽象而不是具体实现
8.2 何时使用类#
当需要创建多个相似对象时
当数据和行为密切相关时
当需要继承和多态时
当系统复杂度增加,需要模块化时
8.3 常见注意事项#
避免过度设计,简单的函数可能更好
优先使用组合而不是继承
保持类的小而专注
使用有意义的命名
为公共接口添加文档字符串
class GoodPracticeExample:
"""
这是一个良好实践示例类。
属性:
name (str): 对象名称
value (int): 对象值
"""
def __init__(self, name, value):
self.name = name
self.value = value
def process_data(self):
"""处理数据并返回结果"""
# 清晰的逻辑
result = self.value * 2
return result
def display_info(self):
"""显示对象信息"""
return f"{self.name}: {self.value}"