深入解析:Python 类基础详解

news/2025/10/1 17:54:53/文章来源:https://www.cnblogs.com/slgkaifa/p/19122608

深入解析:Python 类基础详解

️ Python类基础详解 - 从入门到精通

目录

1. 什么是类

1.1 基本概念

**类(Class)**是Python中面向对象编程的核心概念,它是创建对象的蓝图或模板。

简单理解:

类就像是一个表格模板

比如学生登记表模板:

姓名: _______
年龄: _______
学号: _______

对象就是根据这个模板填写的具体表格

  • 张三的登记表 = 对象1
  • 李四的登记表 = 对象2
  • 王五的登记表 = 对象3

每个表格都有相同的栏目,但填写的内容不同

张三的表格:姓名=张三, 年龄=20, 学号=2024001
李四的表格:姓名=李四, 年龄=19, 学号=2024002
王五的表格:姓名=王五, 年龄=21, 学号=2024003

1.2 生活中的例子

# 想象一下学生登记表
# 学生登记表模板 = 类(Student)
# 根据模板填写的表格 = 对象(student1, student2, student3)
# 所有表格都有:姓名、年龄、学号
# 但每张表格的具体内容不同:
# student1: 姓名="张三", 年龄=20, 学号="2024001"
# student2: 姓名="李四", 年龄=19, 学号="2024002"
# student3: 姓名="王五", 年龄=21, 学号="2024003"

2. 创建第一个类

2.1 最简单的类

# 创建一个空的类
class Person:
"""人类 - 最简单的类定义"""
pass  # pass表示什么都不做,只是占位符
# 创建对象(也叫实例)
person1 = Person()  # 用Person类创建一个对象,叫person1
person2 = Person()  # 用Person类创建另一个对象,叫person2
# 查看对象的类型和内容
print(type(person1))  # 显示person1的类型:<class '__main__.Person'>print(person1)       # 显示person1的内容:<__main__.Person object at 0x...>

2.2 添加属性

class Person:
"""人类 - 添加属性"""
def __init__(self):
"""构造函数 - 创建对象时自动运行"""
self.name = "未知"    # 给对象添加name属性,默认值是"未知"
self.age = 0         # 给对象添加age属性,默认值是0
self.gender = "未知"  # 给对象添加gender属性,默认值是"未知"
# 创建对象
person1 = Person()  # 创建第一个Person对象
person2 = Person()  # 创建第二个Person对象
# 访问对象的属性(查看对象的信息)
print(f"姓名: {person1.name}")    # 显示person1的姓名
print(f"年龄: {person1.age}")      # 显示person1的年龄
print(f"性别: {person1.gender}")   # 显示person1的性别

3. 构造函数__init__

3.1 什么是构造函数__init__?为什么要用它?

问题: 什么是构造函数__init__?为什么要用它?

答案:__init__是Python中的构造函数,它在创建对象时自动运行,用来初始化对象的属性。

用表格比喻理解:

为什么需要构造函数?

# 没有构造函数的问题
class BadStudent:
"""不好的学生类 - 没有构造函数"""
pass
# 创建对象
student = BadStudent()
# 问题1:对象是空的,没有任何属性
print(f"学生姓名: {student.name}")  # 会报错!AttributeError
# 问题2:每次都要手动添加属性,很麻烦
student.name = "张三"      # 手动添加姓名
student.age = 20          # 手动添加年龄
student.student_id = "2024001"  # 手动添加学号
# 问题3:容易遗漏属性
# 如果忘记添加某个属性,程序就会出错

有构造函数的好处:

# 有构造函数的好处
class GoodStudent:
"""好的学生类 - 有构造函数"""
def __init__(self, name, age, student_id):
"""构造函数 - 自动初始化学生信息"""
print(f"正在创建学生: {name}")  # 显示创建过程
self.name = name           # 自动设置姓名
self.age = age            # 自动设置年龄
self.student_id = student_id  # 自动设置学号
self.grades = []          # 自动创建成绩列表
print(f"学生 {name} 创建完成")  # 显示创建完成
# 创建对象(自动调用__init__)
student = GoodStudent("张三", 20, "2024001")
# 好处1:对象创建时就有完整属性
print(f"学生姓名: {student.name}")      # 正常显示
print(f"学生年龄: {student.age}")        # 正常显示
print(f"学生学号: {student.student_id}")  # 正常显示
# 好处2:不会遗漏任何属性
print(f"成绩列表: {student.grades}")     # 正常显示

运行结果:

正在创建学生: 张三
学生 张三 创建完成
学生姓名: 张三
学生年龄: 20
学生学号: 2024001
成绩列表: []

总结:

  • 没有构造函数:对象是空的,容易出错,使用麻烦
  • 有构造函数:对象创建时就有完整属性,使用方便,不容易出错

3.2 为什么要初始化赋值?

问题: 为什么不能直接给对象添加属性,而要在__init__中初始化?

答案: 因为对象刚创建时是"空的",没有任何属性。我们需要给它添加属性并设置初始值。

# 错误的方式:不初始化赋值
class BadStudent:
"""不好的学生类 - 没有初始化"""
pass
# 创建对象
student = BadStudent()
# 尝试访问属性(会报错!)
try:
print(student.name)  # 会报错:AttributeError
except AttributeError as e:
print(f"错误: {e}")
# 正确的方式:初始化赋值
class GoodStudent:
"""好的学生类 - 有初始化"""
def __init__(self, name, age):
"""初始化学生属性"""
self.name = name  # 给对象添加name属性
self.age = age    # 给对象添加age属性
# 创建对象
student = GoodStudent("张三", 20)
# 现在可以安全访问属性
print(f"姓名: {student.name}")  # 正常显示:姓名: 张三
print(f"年龄: {student.age}")   # 正常显示:年龄: 20

总结:

  • 不初始化:对象是空的,访问属性会报错
  • 初始化赋值:对象有属性,可以安全使用

3.3 用表格比喻理解初始化赋值

想象一下制作学生登记表的过程:

# 方式1:制作空白表格(不初始化)
class EmptyTable:
"""空白表格 - 没有填写任何信息"""
pass
# 制作空白表格
table1 = EmptyTable()
# 尝试查看表格内容(会出错!)
try:
print(table1.name)  # 表格上还没有姓名栏
except AttributeError:
print("表格上还没有姓名栏!")
# 方式2:制作填写好的表格(初始化赋值)
class FilledTable:
"""填写好的表格 - 已经填写了基本信息"""
def __init__(self, name, age, student_id):
"""制作表格时自动填写信息"""
self.name = name        # 在姓名栏填写姓名
self.age = age         # 在年龄栏填写年龄
self.student_id = student_id  # 在学号栏填写学号
print(f"正在制作 {name} 的登记表...")
# 制作填写好的表格
table2 = FilledTable("张三", 20, "2024001")
# 现在可以安全查看表格内容
print(f"姓名栏: {table2.name}")
print(f"年龄栏: {table2.age}")
print(f"学号栏: {table2.student_id}")

运行结果:

表格上还没有姓名栏!
正在制作 张三 的登记表...
姓名栏: 张三
年龄栏: 20
学号栏: 2024001

比喻总结:

  • 不初始化 = 制作空白表格,没有填写任何信息
  • 初始化赋值 = 制作表格时自动填写基本信息
  • 访问属性 = 查看表格上的具体信息

3.4 构造函数的详细示例

现在让我们看一个完整的构造函数示例:

class Student:
"""学生类 - 演示构造函数"""
def __init__(self, name, age, student_id):
"""构造函数 - 初始化学生信息
参数说明:
- name: 学生姓名
- age: 学生年龄
- student_id: 学生学号
"""
print(f"正在创建学生: {name}")  # 显示创建过程
self.name = name           # 把传入的name赋值给对象的name属性
self.age = age            # 把传入的age赋值给对象的age属性
self.student_id = student_id  # 把传入的student_id赋值给对象的student_id属性
self.grades = []          # 创建一个空的成绩列表
print(f"学生 {name} 创建完成")  # 显示创建完成
# 创建学生对象(会自动调用__init__方法)
student1 = Student("张三", 20, "2024001")  # 创建张三的学生对象
student2 = Student("李四", 19, "2024002")  # 创建李四的学生对象
# 查看创建好的学生信息
print(f"学生1: {student1.name}, 年龄: {student1.age}")
print(f"学生2: {student2.name}, 年龄: {student2.age}")

3.5 默认参数

class Book:
"""图书类 - 演示默认参数"""
def __init__(self, title, author, pages=100, price=0.0):
"""构造函数 - 带默认参数
参数说明:
- title: 书名(必须提供)
- author: 作者(必须提供)
- pages: 页数(可选,默认100页)
- price: 价格(可选,默认0.0元)
"""
self.title = title      # 设置书名
self.author = author    # 设置作者
self.pages = pages      # 设置页数
self.price = price      # 设置价格
self.is_available = True  # 设置是否可借阅
# 使用默认参数创建对象
book1 = Book("Python编程", "张三")  # 只提供书名和作者,页数和价格用默认值
book2 = Book("Java编程", "李四", 200, 59.9)  # 提供所有参数
# 显示图书信息
print(f"《{book1.title}》- {book1.author}, {book1.pages}页, {book1.price}元")
print(f"《{book2.title}》- {book2.author}, {book2.pages}页, {book2.price}元")

4. 实例属性和方法

4.1 什么是实例属性?

问题: 什么是实例属性?为什么要用实例属性?

答案: 实例属性是属于特定对象的属性,每个对象都有自己独立的属性值。

用表格比喻理解:

4.2 实例属性的特点

实例属性有以下特点:

  1. 独立性:每个对象都有自己独立的属性值
  2. 可变性:可以修改对象的属性值
  3. 互不影响:修改一个对象的属性不会影响其他对象

4.3 实例属性的实践示例

现在让我们看一个具体的例子:

class Car:
"""汽车类 - 演示实例属性"""
def __init__(self, brand, model, color, price):
"""构造函数 - 初始化汽车属性"""
self.brand = brand      # 汽车品牌(每个汽车对象都有自己的品牌)
self.model = model      # 汽车型号(每个汽车对象都有自己的型号)
self.color = color      # 汽车颜色(每个汽车对象都有自己的颜色)
self.price = price      # 汽车价格(每个汽车对象都有自己的价格)
self.mileage = 0        # 里程数(新车的里程数都是0)
self.is_running = False # 是否运行中(新车默认是关闭状态)
# 创建汽车对象
car1 = Car("奔驰", "C200", "黑色", 350000)  # 创建第一辆汽车
car2 = Car("宝马", "X3", "白色", 450000)   # 创建第二辆汽车
# 每个对象都有独立的属性(互不影响)
print(f"汽车1: {car1.brand} {car1.model}, 颜色: {car1.color}")
print(f"汽车2: {car2.brand} {car2.model}, 颜色: {car2.color}")
# 修改一个对象的属性不会影响另一个对象
car1.mileage = 10000  # 给第一辆汽车设置里程数
print(f"汽车1里程: {car1.mileage}")  # 显示第一辆汽车的里程数
print(f"汽车2里程: {car2.mileage}")  # 第二辆汽车的里程数还是0

4.4 什么是实例方法?

问题: 什么是实例方法?为什么要用实例方法?

答案: 实例方法是定义在类中的函数,可以访问和修改实例属性。

用表格比喻理解:

  • 实例方法就像表格上的操作按钮
  • 可以查看表格内容(读取属性)
  • 可以修改表格内容(修改属性)
  • 可以执行表格相关的操作

4.5 实例方法的实践示例

现在让我们看一个具体的例子:

class Car:
"""汽车类 - 演示实例方法"""
def __init__(self, brand, model, color, price):
"""构造函数 - 初始化汽车属性"""
self.brand = brand      # 汽车品牌
self.model = model      # 汽车型号
self.color = color      # 汽车颜色
self.price = price      # 汽车价格
self.mileage = 0        # 里程数(初始为0)
self.is_running = False # 引擎状态(初始为关闭)
def start_engine(self):
"""启动引擎方法"""
if not self.is_running:  # 如果引擎没有运行
self.is_running = True  # 设置引擎状态为运行
print(f"{self.brand} {self.model} 引擎已启动")
else:  # 如果引擎已经在运行
print(f"{self.brand} {self.model} 引擎已经在运行")
def stop_engine(self):
"""关闭引擎方法"""
if self.is_running:  # 如果引擎正在运行
self.is_running = False  # 设置引擎状态为关闭
print(f"{self.brand} {self.model} 引擎已关闭")
else:  # 如果引擎已经关闭
print(f"{self.brand} {self.model} 引擎已经关闭")
def drive(self, distance):
"""驾驶汽车方法
参数:
- distance: 要行驶的距离(公里)
"""
if self.is_running:  # 如果引擎正在运行
self.mileage += distance  # 增加里程数
print(f"{self.brand} {self.model} 行驶了{distance}公里")
print(f"总里程: {self.mileage}公里")
else:  # 如果引擎没有运行
print("请先启动引擎")
def get_info(self):
"""获取汽车信息方法"""
status = "运行中" if self.is_running else "已关闭"  # 根据引擎状态设置状态文字
return f"{self.brand} {self.model} ({self.color}) - {status} - 里程: {self.mileage}公里"
# 使用实例方法
car = Car("特斯拉", "Model 3", "蓝色", 300000)  # 创建一辆特斯拉汽车
print(car.get_info())  # 显示汽车信息
car.start_engine()     # 启动引擎
car.drive(50)          # 行驶50公里
car.drive(30)          # 再行驶30公里
car.stop_engine()      # 关闭引擎
print(car.get_info())  # 再次显示汽车信息

5. 类属性和类方法

5.1 什么是类属性?

问题: 什么是类属性?为什么要用类属性?

答案: 类属性是属于类本身的属性,所有对象共享同一个类属性。

用表格比喻理解:

5.2 类属性的特点

类属性有以下特点:

  1. 共享性:所有对象共享同一个类属性
  2. 全局性:修改类属性会影响所有对象
  3. 持久性:类属性在程序运行期间一直存在

5.3 类属性的实践示例

现在让我们看一个具体的例子:

class Car:
"""汽车类 - 演示类属性"""
# 类属性 - 所有实例共享
wheels = 4
engine_type = "内燃机"
manufacturer = "未知制造商"
def __init__(self, brand, model, color, price):
"""构造函数"""
self.brand = brand      # 实例属性
self.model = model      # 实例属性
self.color = color      # 实例属性
self.price = price      # 实例属性
def get_class_info(self):
"""获取类信息"""
return f"轮子数: {Car.wheels}, 引擎类型: {Car.engine_type}, 制造商: {Car.manufacturer}"
# 创建汽车对象
car1 = Car("奔驰", "C200", "黑色", 350000)
car2 = Car("宝马", "X3", "白色", 450000)
# 访问类属性
print(f"汽车轮子数: {Car.wheels}")
print(f"引擎类型: {Car.engine_type}")
# 通过实例访问类属性
print(car1.get_class_info())
print(car2.get_class_info())
# 修改类属性会影响所有实例
Car.wheels = 6
Car.engine_type = "电动"
print("修改类属性后:")
print(car1.get_class_info())
print(car2.get_class_info())

5.4 什么是类方法?为什么要用类方法?

问题: 为什么要有类方法?它和普通方法有什么区别?

答案: 类方法是专门用来操作类属性的方法,而不是操作对象属性的方法。

# 普通方法 vs 类方法的区别
class Student:
"""学生类 - 演示普通方法和类方法的区别"""
# 类属性 - 所有学生共享
school_name = "厦门工学院"
total_count = 0
def __init__(self, name, age):
"""构造函数"""
self.name = name  # 实例属性 - 每个学生独有
self.age = age    # 实例属性 - 每个学生独有
Student.total_count += 1  # 每创建一个学生,总数+1
# 普通方法(实例方法)- 操作对象属性
def get_student_info(self):
"""获取学生信息 - 普通方法"""
return f"学生: {self.name}, 年龄: {self.age}"
# 类方法 - 操作类属性
@classmethod
def get_school_info(cls):
"""获取学校信息 - 类方法"""
return f"学校: {cls.school_name}, 总学生数: {cls.total_count}"
@classmethod
def set_school_name(cls, new_name):
"""设置学校名称 - 类方法"""
cls.school_name = new_name
print(f"学校名称已更改为: {new_name}")
# 使用示例
student1 = Student("张三", 20)
student2 = Student("李四", 19)
# 使用普通方法(需要对象)
print(student1.get_student_info())  # 需要student1对象
print(student2.get_student_info())  # 需要student2对象
# 使用类方法(不需要对象,直接用类名)
print(Student.get_school_info())  # 直接用Student类名
Student.set_school_name("厦门大学")  # 直接用Student类名
print(Student.get_school_info())

运行结果:

学生: 张三, 年龄: 20
学生: 李四, 年龄: 19
学校: 厦门工学院, 总学生数: 2
学校名称已更改为: 厦门大学
学校: 厦门大学, 总学生数: 2

总结对比:

方法类型操作对象调用方式用途
普通方法对象属性对象.方法()处理单个对象的信息
类方法类属性类名.方法()处理所有对象共享的信息

5.5 类方法的实践示例

类方法是使用@classmethod装饰器定义的方法,第一个参数是类本身(通常命名为cls)。

class Car:
"""汽车类 - 演示类方法"""
wheels = 4
manufacturer = "未知制造商"
total_cars = 0  # 总汽车数量
def __init__(self, brand, model, color, price):
"""构造函数"""
self.brand = brand
self.model = model
self.color = color
self.price = price
Car.total_cars += 1  # 每创建一个汽车,总数+1
@classmethod
def set_manufacturer(cls, manufacturer_name):
"""设置制造商 - 类方法"""
cls.manufacturer = manufacturer_name
print(f"制造商已设置为: {manufacturer_name}")
@classmethod
def get_total_cars(cls):
"""获取总汽车数量 - 类方法"""
return cls.total_cars
@classmethod
def create_tesla(cls, model, color, price):
"""创建特斯拉汽车 - 类方法"""
return cls("特斯拉", model, color, price)
def get_info(self):
"""获取汽车信息"""
return f"{self.brand} {self.model} ({self.color}) - {self.price}元"
# 使用类方法
print(f"总汽车数: {Car.get_total_cars()}")
# 创建汽车
car1 = Car("奔驰", "C200", "黑色", 350000)
car2 = Car("宝马", "X3", "白色", 450000)
print(f"总汽车数: {Car.get_total_cars()}")
# 设置制造商
Car.set_manufacturer("德国汽车集团")
# 使用类方法创建特定品牌的汽车
tesla = Car.create_tesla("Model S", "红色", 500000)
print(tesla.get_info())

6. 静态方法

6.1 什么是静态方法?为什么要用静态方法?

问题: 什么是静态方法?为什么要用静态方法?

答案: 静态方法是不需要访问类属性或对象属性的工具函数,它就像一个独立的计算器。

用表格比喻理解:

6.2 静态方法的特点

静态方法有以下特点:

  1. 独立性:不需要访问类属性或对象属性
  2. 工具性:只是用来执行特定的计算或操作
  3. 通用性:可以在任何地方调用,不依赖对象

6.3 静态方法的实践示例

现在让我们看一个具体的例子:

# 三种方法的对比
class Calculator:
"""计算器类 - 演示三种方法的区别"""
# 类属性
brand = "卡西欧"
def __init__(self):
"""构造函数"""
self.result = 0  # 实例属性
# 普通方法(实例方法)- 操作对象属性
def add(self, number):
"""加法 - 普通方法"""
self.result += number  # 修改对象属性
return self.result
# 类方法 - 操作类属性
@classmethod
def get_brand(cls):
"""获取品牌 - 类方法"""
return cls.brand  # 访问类属性
# 静态方法 - 不操作任何属性,只是工具函数
@staticmethod
def calculate_circle_area(radius):
"""计算圆面积 - 静态方法"""
import math
return math.pi * radius ** 2  # 不访问任何属性,只是计算
# 使用示例
calc = Calculator()
# 使用普通方法(需要对象)
print(calc.add(5))  # 需要calc对象
print(calc.add(3))  # 需要calc对象
# 使用类方法(不需要对象,但需要类)
print(Calculator.get_brand())  # 需要Calculator类
# 使用静态方法(不需要对象,也不需要类)
area = Calculator.calculate_circle_area(5)  # 直接用类名调用
print(f"圆面积: {area:.2f}")
# 静态方法也可以这样调用(但通常不这样做)
calc2 = Calculator()
area2 = calc2.calculate_circle_area(3)  # 通过对象调用(不推荐)
print(f"圆面积: {area2:.2f}")

运行结果:

5
8
卡西欧
圆面积: 78.54
圆面积: 28.27

总结对比:

方法类型操作对象调用方式用途是否需要对象
普通方法对象属性对象.方法()处理单个对象的信息需要
类方法类属性类名.方法()处理所有对象共享的信息不需要
静态方法类名.方法()工具函数,不依赖类或对象不需要

6.4 三种方法的总结对比

用表格比喻来理解三种方法:

class StudentTable:
"""学生登记表类 - 演示三种方法"""
# 类属性 - 所有表格共享
school_name = "厦门工学院"
total_tables = 0
def __init__(self, name, age):
"""构造函数"""
self.name = name  # 实例属性 - 每张表格独有
self.age = age    # 实例属性 - 每张表格独有
StudentTable.total_tables += 1
# 普通方法 - 操作单张表格的内容
def get_student_info(self):
"""查看学生信息 - 普通方法"""
return f"姓名: {self.name}, 年龄: {self.age}"
# 类方法 - 操作所有表格的公共信息
@classmethod
def get_school_info(cls):
"""查看学校信息 - 类方法"""
return f"学校: {cls.school_name}, 总表格数: {cls.total_tables}"
# 静态方法 - 工具函数,不操作表格
@staticmethod
def calculate_age_in_days(age):
"""计算年龄对应的天数 - 静态方法"""
return age * 365  # 不操作任何表格,只是计算
# 使用示例
table1 = StudentTable("张三", 20)
table2 = StudentTable("李四", 19)
# 普通方法:查看单张表格的内容
print(table1.get_student_info())  # 查看张三的表格
print(table2.get_student_info())  # 查看李四的表格
# 类方法:查看所有表格的公共信息
print(StudentTable.get_school_info())  # 查看学校信息
# 静态方法:使用工具函数
days1 = StudentTable.calculate_age_in_days(20)  # 计算20岁对应的天数
days2 = StudentTable.calculate_age_in_days(19)  # 计算19岁对应的天数
print(f"张三的年龄相当于 {days1} 天")
print(f"李四的年龄相当于 {days2} 天")

运行结果:

姓名: 张三, 年龄: 20
姓名: 李四, 年龄: 19
学校: 厦门工学院, 总表格数: 2
张三的年龄相当于 7300 天
李四的年龄相当于 6935 天

比喻总结:

方法类型表格比喻操作对象调用方式
普通方法查看单张表格的内容对象属性对象.方法()
类方法查看所有表格的公共信息类属性类名.方法()
静态方法使用计算器(工具)类名.方法()

什么时候用哪种方法?

  • 普通方法:需要处理单个对象的信息时
  • 类方法:需要处理所有对象共享的信息时
  • 静态方法:需要工具函数,不依赖对象或类时
class MathUtils:
"""数学工具类 - 演示静态方法"""
@staticmethod
def add(a, b):
"""加法"""
return a + b
@staticmethod
def multiply(a, b):
"""乘法"""
return a * b
@staticmethod
def is_even(number):
"""判断是否为偶数"""
return number % 2 == 0
@staticmethod
def calculate_circle_area(radius):
"""计算圆的面积"""
import math
return math.pi * radius ** 2
@staticmethod
def calculate_distance(x1, y1, x2, y2):
"""计算两点间距离"""
import math
return math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
# 使用静态方法
print(f"5 + 3 = {MathUtils.add(5, 3)}")
print(f"4 * 6 = {MathUtils.multiply(4, 6)}")
print(f"8是偶数吗: {MathUtils.is_even(8)}")
print(f"半径为5的圆面积: {MathUtils.calculate_circle_area(5):.2f}")
print(f"两点间距离: {MathUtils.calculate_distance(0, 0, 3, 4):.2f}")
# 也可以通过实例调用静态方法
math_utils = MathUtils()
print(f"通过实例调用: {math_utils.add(10, 20)}")

7. 属性访问控制

7.1 什么是属性访问控制?

问题: 什么是属性访问控制?为什么要控制属性访问?

答案: 属性访问控制是控制外部代码如何访问和修改对象属性的机制。

用表格比喻理解:

7.2 公有属性

什么是公有属性?
公有属性是可以从外部直接访问和修改的属性。

class BankAccount:
"""银行账户类 - 演示公有属性"""
def __init__(self, account_holder, initial_balance=0):
"""构造函数"""
self.account_holder = account_holder  # 公有属性
self.balance = initial_balance        # 公有属性
self.account_number = "ACC" + str(id(self))  # 公有属性
# 创建账户
account = BankAccount("张三", 1000)
# 可以直接访问和修改公有属性
print(f"账户持有人: {account.account_holder}")
print(f"余额: {account.balance}")
print(f"账户号: {account.account_number}")
# 可以直接修改余额(不安全)
account.balance = 10000  # 危险!直接修改余额
print(f"修改后余额: {account.balance}")

7.2 受保护属性

使用单下划线_前缀表示受保护属性,约定不应该从外部直接访问。

class BankAccount:
"""银行账户类 - 演示受保护属性"""
def __init__(self, account_holder, initial_balance=0):
"""构造函数"""
self.account_holder = account_holder
self._balance = initial_balance      # 受保护属性
self._transaction_count = 0         # 受保护属性
def deposit(self, amount):
"""存款"""
if amount > 0:
self._balance += amount
self._transaction_count += 1
print(f"存款成功,余额: {self._balance}")
else:
print("存款金额必须大于0")
def withdraw(self, amount):
"""取款"""
if amount > 0:
if amount <= self._balance:
self._balance -= amount
self._transaction_count += 1
print(f"取款成功,余额: {self._balance}")
else:
print("余额不足")
else:
print("取款金额必须大于0")
def get_balance(self):
"""获取余额"""
return self._balance
def get_transaction_count(self):
"""获取交易次数"""
return self._transaction_count
# 使用受保护属性
account = BankAccount("李四", 2000)
# 推荐通过方法访问
account.deposit(500)
account.withdraw(200)
print(f"余额: {account.get_balance()}")
print(f"交易次数: {account.get_transaction_count()}")
# 仍然可以直接访问(但不推荐)
print(f"直接访问余额: {account._balance}")

7.3 私有属性

什么是私有属性?
私有属性是不能从外部直接访问的属性,只能通过类内部的方法访问。

用表格比喻理解:

  • 私有属性就像表格中的机密信息
  • 外部人员不能直接查看
  • 只能通过特定的方法(如验证身份后)才能查看
class BankAccount:
"""银行账户类 - 演示私有属性"""
def __init__(self, account_holder, initial_balance=0):
"""构造函数"""
self.account_holder = account_holder
self.__balance = initial_balance        # 私有属性
self.__transaction_history = []        # 私有属性
self.__pin = "1234"                    # 私有属性
def deposit(self, amount):
"""存款"""
if amount > 0:
self.__balance += amount
self.__transaction_history.append(f"存款: +{amount}")
print(f"存款成功,余额: {self.__balance}")
else:
print("存款金额必须大于0")
def withdraw(self, amount, pin):
"""取款"""
if pin != self.__pin:
print("密码错误")
return
if amount > 0:
if amount <= self.__balance:
self.__balance -= amount
self.__transaction_history.append(f"取款: -{amount}")
print(f"取款成功,余额: {self.__balance}")
else:
print("余额不足")
else:
print("取款金额必须大于0")
def get_balance(self):
"""获取余额"""
return self.__balance
def get_transaction_history(self):
"""获取交易历史"""
return self.__transaction_history.copy()
def change_pin(self, old_pin, new_pin):
"""修改密码"""
if old_pin == self.__pin:
self.__pin = new_pin
print("密码修改成功")
else:
print("原密码错误")
# 使用私有属性
account = BankAccount("王五", 3000)
# 正常操作
account.deposit(1000)
account.withdraw(500, "1234")
account.withdraw(100, "0000")  # 密码错误
# 获取信息
print(f"余额: {account.get_balance()}")
print("交易历史:")
for transaction in account.get_transaction_history():
print(f"  {transaction}")
# 尝试直接访问私有属性(会失败)
try:
print(account.__balance)  # 会报错
except AttributeError as e:
print(f"无法访问私有属性: {e}")
# 修改密码
account.change_pin("1234", "5678")
account.withdraw(200, "5678")

8. 实际应用示例

8.1 学生成绩管理系统

现在让我们用学到的知识创建一个完整的学生成绩管理系统:

class Student:
"""学生类 - 成绩管理系统"""
# 类属性
school_name = "厦门工学院"
total_students = 0
def __init__(self, name, student_id, major):
"""构造函数"""
self.name = name
self.student_id = student_id
self.major = major
self.courses = {}  # 课程成绩字典
self.gpa = 0.0
Student.total_students += 1
def add_course(self, course_name, grade):
"""添加课程成绩"""
if 0 <= grade <= 100:
self.courses[course_name] = grade
self._calculate_gpa()
print(f"{self.name}{course_name}成绩已添加: {grade}")
else:
print("成绩必须在0-100之间")
def remove_course(self, course_name):
"""删除课程"""
if course_name in self.courses:
del self.courses[course_name]
self._calculate_gpa()
print(f"{self.name}{course_name}课程已删除")
else:
print(f"{self.name}没有选修{course_name}")
def _calculate_gpa(self):
"""计算GPA(私有方法)"""
if self.courses:
self.gpa = sum(self.courses.values()) / len(self.courses)
else:
self.gpa = 0.0
def get_course_count(self):
"""获取课程数量"""
return len(self.courses)
def get_best_course(self):
"""获取最高分课程"""
if self.courses:
best_course = max(self.courses, key=self.courses.get)
return best_course, self.courses[best_course]
return None, 0
def get_worst_course(self):
"""获取最低分课程"""
if self.courses:
worst_course = min(self.courses, key=self.courses.get)
return worst_course, self.courses[worst_course]
return None, 0
def get_student_info(self):
"""获取学生信息"""
return f"""
学生信息:
姓名: {self.name}
学号: {self.student_id}
专业: {self.major}
学校: {Student.school_name}
课程数量: {self.get_course_count()}
GPA: {self.gpa:.2f}
"""
@classmethod
def get_school_info(cls):
"""获取学校信息"""
return f"学校: {cls.school_name}, 总学生数: {cls.total_students}"
@staticmethod
def grade_to_letter(grade):
"""成绩转换为等级"""
if grade >= 90:
return "A"
elif grade >= 80:
return "B"
elif grade >= 70:
return "C"
elif grade >= 60:
return "D"
else:
return "F"
# 使用学生管理系统
print("=== 学生成绩管理系统 ===")
# 创建学生
student1 = Student("张三", "2024001", "计算机科学")
student2 = Student("李四", "2024002", "软件工程")
# 添加课程成绩
student1.add_course("Python编程", 85)
student1.add_course("数据结构", 92)
student1.add_course("算法设计", 78)
student1.add_course("数据库", 88)
student2.add_course("Java编程", 90)
student2.add_course("Web开发", 85)
student2.add_course("软件工程", 82)
# 显示学生信息
print(student1.get_student_info())
print(student2.get_student_info())
# 获取最高分和最低分课程
best_course, best_grade = student1.get_best_course()
worst_course, worst_grade = student1.get_worst_course()
print(f"{student1.name}最高分课程: {best_course} ({best_grade}分)")
print(f"{student1.name}最低分课程: {worst_course} ({worst_grade}分)")
# 成绩等级转换
print(f"85分对应等级: {Student.grade_to_letter(85)}")
print(f"78分对应等级: {Student.grade_to_letter(78)}")
# 学校信息
print(Student.get_school_info())

9. 最佳实践

9.1 命名规范

类名: 使用大驼峰命名法(PascalCase)
方法名: 使用小驼峰命名法(camelCase)或下划线命名法(snake_case)
属性名: 使用下划线命名法(snake_case)

class UserAccount:
"""用户账户类 - 遵循命名规范"""
# 类属性使用大写
MAX_LOGIN_ATTEMPTS = 3
DEFAULT_BALANCE = 0.0
def __init__(self, username, email):
# 实例属性使用小写
self.username = username
self.email = email
self._balance = UserAccount.DEFAULT_BALANCE  # 受保护属性
self.__login_attempts = 0  # 私有属性
# 公共方法使用小写
def deposit(self, amount):
"""存款"""
pass
# 私有方法使用双下划线
def __validate_amount(self, amount):
"""验证金额"""
return amount > 0
# 属性访问器
@property
def balance(self):
"""余额属性"""
return self._balance
@balance.setter
def balance(self, value):
"""设置余额"""
if value >= 0:
self._balance = value
else:
raise ValueError("余额不能为负数")

9.2 类设计原则

单一职责原则:每个类只负责一个功能
开闭原则:对扩展开放,对修改关闭
里氏替换原则:子类可以替换父类
接口隔离原则:使用多个专门的接口,而不是一个总接口

class Student:
"""学生类 - 遵循单一职责原则"""
def __init__(self, name, age):
self.name = name
self.age = age
def get_info(self):
"""获取学生信息"""
return f"姓名: {self.name}, 年龄: {self.age}"
class StudentGradeManager:
"""学生成绩管理类 - 专门负责成绩管理"""
def __init__(self, student):
self.student = student
self.grades = {}
def add_grade(self, subject, grade):
"""添加成绩"""
self.grades[subject] = grade
def get_average(self):
"""计算平均分"""
if self.grades:
return sum(self.grades.values()) / len(self.grades)
return 0
# 使用示例
student = Student("张三", 20)
grade_manager = StudentGradeManager(student)
grade_manager.add_grade("数学", 85)
grade_manager.add_grade("英语", 90)
print(student.get_info())
print(f"平均分: {grade_manager.get_average()}")

10. 学习要点总结

10.1 核心概念回顾

类定义:使用class关键字定义类,类名使用大驼峰命名
构造函数__init__方法用于初始化对象属性
实例属性:每个对象都有独立的属性值
实例方法:可以访问和修改实例属性的方法
类属性:所有实例共享的属性
类方法:使用@classmethod装饰器,操作类属性
静态方法:使用@staticmethod装饰器,不依赖类或实例
访问控制:使用___控制属性访问级别

10.2 练习建议

练习建议:

  1. 创建一个Rectangle类,计算面积和周长
  2. 设计一个BankAccount类,实现存款、取款功能
  3. 实现一个Library类,管理图书借阅
  4. 创建一个Employee类,计算工资和奖金

厦门工学院人工智能创作坊 --郑恩赐
2025年9月29日

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/924089.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网站单页发布wordpress标题关键词描述

解耦 解耦是指解除不同模块或系统之间的紧密关联或相互依赖关系。 在技术领域&#xff0c;通过解耦可以使各个部分相对独立地进行开发、维护和修改&#xff0c;而不会对其他部分产生过多的直接影响。 这样能提高系统的灵活性、可扩展性和可维护性。 常见解耦方式 包括&…

手机ftp传网站文件在哪里wordpress hta

怎么把mov格式的视频转换mp4&#xff1f;在这个数字化时代&#xff0c;视频已经跻身为生活的核心元素&#xff0c;然而&#xff0c;制作和分享视频时选择合适的格式变得至关重要&#xff0c;在庞大的视频格式库中&#xff0c;我们熟知的包括mov和MP4&#xff0c;它们各有特色&a…

凯里网站设计仪征网站建设公司哪家好

1、基本语法 在python中&#xff0c;一般处理和捕获异常会用到这个结构&#xff1a; try:python程序 except 错误类型1:python程序 except 错误类型2:python程序 except 其他错误类型:python程序 finally:python程序首先一定会进入try中执行try的python程序如果报错 则进入exc…

信创PC收藏网址

重磅更新 |《2025年上半年信创PC竞争力矩阵》出炉! https://mp.weixin.qq.com/s/dEnKdrKgkW6N27TUY_4J2g

AI Coding 让我两天完成图像编辑器 Monica 的国际化与多主题

AI Coding 让我两天完成图像编辑器 Monica 的国际化与多主题2025-10-01 17:41 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !importa…

线程同步实战指南:从 bug 根源到锁优化的终极之路 - 教程

线程同步实战指南:从 bug 根源到锁优化的终极之路 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consola…

2025 年数据恢复系统推荐转转大师数据恢复,深度剖析各款系统平台核心优势与适用场景数据恢复系统推荐指南

行业背景2025 年中国数据恢复软件市场迎来爆发式增长,预计规模将突破 85 亿元人民币,年复合增长率达 28.6%,数字化转型加速与数据安全意识提升成为核心驱动力。技术层面,AI 智能恢复算法与分布式存储架构成为主流,…

2025 年离心泵厂家 TOP 企业品牌推荐排行榜!化工,卧式多级,不锈钢,立式,氟塑料,管道,衬氟,耐腐蚀离心泵推荐这十家公司!

在工业领域中,离心泵作为流体输送的关键设备,广泛应用于化工、石油、电力、冶金等诸多行业。然而,随着市场的不断发展,离心泵制造商如雨后春笋般涌现,产品质量与技术水平参差不齐。如何在众多制造商中挑选出技术先…

做响应式网站设计师如何布局呢网站优化的方式

1.前言   懒加载技术(简称lazyload)并不是新技术, 它是js程序员对网页性能优化的一种方案.lazyload的核心是按需加载.在大型网站中都有lazyload的身影,例如谷歌的图片搜索页,迅雷首页&#xff0c;淘宝网,QQ空间等.因此掌握lazyload技术是个不错的选择,可惜jquery插件lazy loa…

在线PS的强大功能一览:从基础修图到高级合成,还有这3款免费软件推荐!

​ 大家好!今天我们来聊聊在线PS工具,无需下载安装,打开浏览器就能轻松处理图片,真的太方便了!接下来就为大家介绍几项在线PS的实用功能,并推荐一个我最近发现的超好用的网站。 📌 在线PS的五大实用功能: 基础…

详细介绍:抽丝剥茧的Transformer详解

详细介绍:抽丝剥茧的Transformer详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Mona…

2025 年高压氧舱厂家 TOP 推荐榜单揭晓,家用,高原,小型,单人,民用,专业,医用,家庭,智能,进口高压氧舱公司推荐!

随着健康意识的不断提升,高压氧舱作为一种能为用户带来氧疗体验的设备,在医疗保健、日常保养等领域的需求持续增长。然而,当前高压氧舱行业发展并非毫无问题,市场上品牌数量众多,产品质量参差不齐,部分制造商缺乏…

oppoR9m刷Linux系统:开启开发者模式

前言全局说明一、说明 1.1 环境: Windows 7 旗舰版 OppoR9m二、开启,开发者模式 2.1 开启开发者模式 设置 -- 关于手机 - 点击 “版本号” 7次,提示开启“开启开发者模式”2.2 找到开启开发者选项 设置 -- 其他设置 …

macOS 上手记录

近期在某二手平台入手了一台 MacBook Pro,由此开启了 macOS 的使用历程。这里记录一下自己认为有价值的内容。你也可以认为这是一个从 Windows 切换到 macOS 的实用经验贴。 本文可能会不时更新。 设备和系统信息机型…

Google Drive批量转存他人分享的链接的文件

1、将链接文件的快捷方式添加到自己网盘2、安装桌面客户端,到共享目录下复制分享的文件到你要的位置或者右击选可离线使用也会下载到本地(推荐,不然边下边转移可能出问题)或者设置里选镜像模式

异常检测

本文总结和整理所有异常检测算法异常检测知识点汇总 异常检测面临的难点 1.在实际应用场景的大量数据,都没有标签,市面上成熟的监督学习技术都不能使用, 2.区分是噪声或者是异常点也是一个挑战 3.当各种诈骗数据混在…

2025 年物流公司服务 TOP 企业品牌推荐推荐榜,无锡到西安、无锡到太原、无锡到宁波、无锡到郑州、无锡到上海物流公司推荐!

在现代供应链体系中,冷链运输与仓储服务作为保障商品品质的关键环节,其重要性愈发凸显。然而当前物流行业在该领域仍面临诸多突出问题:部分企业冷链运输方式选择单一,未能根据货物特性匹配最优方案,导致货物损耗率…

2025 年曝气器制造厂家 TOP 企业品牌推荐排行榜,微孔 / 平板 / 管式 / 拱形 / 可提升式曝气器公司推荐这 10 家

在环保水处理行业持续发展的当下,曝气器作为污水处理系统中的关键设备,其性能与质量直接影响着污水处理效率和效果。然而,当前市场上曝气器制造企业数量众多,产品种类繁杂,质量参差不齐,给采购方带来了诸多困扰。…

定制型网站建设服务动漫设计速成班

题目描述&#xff1a;将一句话的单词进行倒置&#xff0c;标点不倒置。比如 “I like beijing.”&#xff0c;经过处理后变为&#xff1a;“beijing. like I”。 文章目录 原题目题目描述&#xff1a;输入描述&#xff1a;输出描述&#xff1a;题目链接&#xff1a; 整体思路分…

深入解析:基于海思Hi3798MV200Android7.0聊聊HDMI色深模式和电视HDR

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …