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装饰器,不需要selfcls参数

    • 类似于普通函数,但逻辑上属于类

    • 不能访问实例属性或类属性,仅提供工具功能

核心区别:

  • 实例方法操作对象数据,类方法操作类数据,静态方法执行独立功能

  • 选择依据:是否需要访问实例属性(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 面向对象设计原则#

  1. 单一职责原则:一个类只负责一个功能领域

  2. 开放封闭原则:对扩展开放,对修改封闭

  3. 里氏替换原则:子类必须能够替换父类

  4. 接口隔离原则:使用多个专门接口比使用单一接口更好

  5. 依赖倒置原则:依赖抽象而不是具体实现

8.2 何时使用类#

  • 当需要创建多个相似对象时

  • 当数据和行为密切相关时

  • 当需要继承和多态时

  • 当系统复杂度增加,需要模块化时

8.3 常见注意事项#

  1. 避免过度设计,简单的函数可能更好

  2. 优先使用组合而不是继承

  3. 保持类的小而专注

  4. 使用有意义的命名

  5. 为公共接口添加文档字符串

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}"