🚗 Python 类属性、类方法与静态方法详解
这份笔记深入解析了 Python 面向对象编程中三个核心概念:类属性、类方法和静态方法,并结合了具体的代码示例和实战练习。
🧠 知识点思维导图
1. 类属性
类属性是属于类本身的数据,而不是属于某个具体对象的。它在所有实例之间共享同一份数据。
核心要点
-
定义位置:类体内,方法之外。
-
共享性:所有实例共享同一个类属性。
-
修改规则:
- 正确方式:使用
类名.属性 = 值修改,会影响所有实例。 - 错误/陷阱方式:使用
实例.属性 = 值修改,不会修改类属性,而是给该实例创建了一个同名的实例属性,仅影响当前实例。
- 正确方式:使用
代码示例
class Car(object):
"""
定义一个汽车类
"""
wheel = 4 # 类属性:所有汽车默认4个轮子
count = 0 # 类属性:统计创建的汽车数量
def __init__(self, brand, color):
self.brand = brand # 实例属性
self.color = color # 实例属性
Car.count += 1 # 创建一辆车,类属性计数加1
def run(self):
print(f"{self.brand}汽车开始行驶")
def __str__(self):
return f"{self.brand}汽车颜色是{self.color},轮子数量是{self.wheel}"
# --- 测试代码 ---
c1 = Car("保时捷", "黑色")
print("1:", c1.count) # 输出: 1
# ⚠️ 陷阱:使用 对象.类属性 修改
c1.wheel = 6
# 解释:这行代码并没有修改 Car 类的 wheel 属性,而是给 c1 对象新增了一个实例属性 wheel
print("2:", c1.wheel) # 输出: 6 (访问的是 c1 的实例属性)
# ✅ 正确:使用 类名.类属性 修改
Car.wheel = 8
# 解释:这行代码修改了类属性,会影响所有未屏蔽该属性的实例
c2 = Car("法拉利", "蓝色")
print("3:", c2.count) # 输出: 2
print("4:", c2.wheel) # 输出: 8 (c2 没有实例属性 wheel,访问的是类属性)
print(c2) # 输出: 法拉利汽车颜色是蓝色,轮子数量是8
小结:一般情况下,建议使用类方法来操作类属性,而不是直接通过类属性操作,这样更安全且易于维护。
运行结果:
2. 类方法
类方法是操作类属性的最佳方式。
核心要点
- 装饰器:
@classmethod - 第一个参数:
cls(约定俗成),代表类本身(例如Car),而不是实例。 - 能力:可以访问和修改类属性(
cls.wheel),也可以创建实例。
代码示例
class Car(object):
"""
定义一个汽车类
"""
wheel = 4
count = 0
def __init__(self, brand, color):
self.brand = brand
self.color = color
Car.count += 1
@classmethod
def get_count(cls):
print(f"创建的汽车数量是:{cls.count}")
@classmethod
def set_wheel(cls, wheel):
cls.wheel = wheel
print(f"设置轮子数量为:{cls.wheel}")
@classmethod
def set_count(cls):
cls.count = 0
print("把汽车数量设置为0,重新计数")
def __str__(self):
return f"{self.brand}汽车颜色是{self.color},轮子数量是{self.wheel}"
# --- 测试代码 ---
car = Car("保时捷", "蓝色")
Car.get_count() # 输出: 创建的汽车数量是:1
car2 = Car("法拉利", "蓝色")
Car.get_count() # 输出: 创建的汽车数量是:2
Car.set_wheel(6) # 通过类方法修改类属性
print(car) # 输出: 保时捷汽车颜色是蓝色,轮子数量是6 (类属性改变,影响所有实例)
运行结果:
3. 静态方法
静态方法通常作为工具方法使用,与类或实例的状态无关。
核心要点
- 装饰器:
@staticmethod - 参数:不需要
self或cls参数。 - 能力:不能直接访问类属性或实例属性(除非手动通过类名访问)。
- 用途:逻辑上属于该类的工具函数(如数据校验、数学计算)。
代码示例
class StudentManage(object):
"""
定义一个学生管理类
"""
@staticmethod
def menu():
print("1.学生登录")
print("2.学生管理")
print("3.退出系统")
@staticmethod
def sum_students(class_count, student_number):
return class_count * student_number
# --- 测试代码 ---
StudentManage.menu()
print(StudentManage.sum_students(5, 20)) # 输出: 100
4. 类方法与静态方法的对比
表格
| 特性 | 类方法 (@classmethod) | 静态方法 (@staticmethod) |
|---|---|---|
| 第一个参数 | cls (类本身) | 无强制参数 |
| 访问类属性 | ✅ 可以访问和修改 (cls.attr) | ❌ 不能直接访问 (需通过类名) |
| 访问实例属性 | ❌ 不能访问 | ❌ 不能访问 |
| 主要用途 | 修改类状态、工厂模式 | 工具函数、逻辑分组 |
| 继承特性 | 支持多态 (调用时 cls 指向子类) | 不具备多态性,行为像普通函数 |
运行结果:
5. 综合实战练习:支付系统
需求:实现一个支付类。
- 实例方法:实现支付功能(扣除余额)。
- 类方法:实现设置支付费率(修改全局费率)。
- 静态方法:实现校验支付金额(工具函数)。
class Payment(object):
pay_rate = 0.05 # 类属性:默认费率 5%
account_balance = 10000 # 类属性:默认账户余额
def __init__(self, balance=0):
# 如果传入了余额,则更新实例的余额(注意:这里实际上创建了实例属性,遮蔽了类属性)
if balance > 0:
self.account_balance = balance
# --- 实例方法 ---
def pay(self, amount):
if amount:
# 计算含手续费的金额
total_cost = amount * (1 + self.pay_rate)
print(f"支付了 {total_cost}元")
self.account_balance -= total_cost
else:
print("请输入正确的支付金额")
# --- 类方法 ---
@classmethod
def set_pay_rate(cls, pay_rate):
cls.pay_rate = pay_rate
# --- 静态方法 ---
@staticmethod
def check_amount(amount):
if 0 < amount <= 5000:
return amount
else:
print("金额超出范围")
return 0
def __str__(self):
return f"账户余额:{self.account_balance}"
# --- 测试流程 ---
payment = Payment()
# 1. 使用静态方法校验金额
amount = Payment.check_amount(1000) # 返回 1000
# 2. 使用实例方法支付 (使用默认费率 0.05)
payment.pay(amount)
# 输出: 支付了 1050.0元
print(payment.pay_rate) # 输出: 0.05
# 3. 使用类方法修改费率
Payment.set_pay_rate(0.08) # 全局费率变为 8%
print(payment.pay_rate) # 输出: 0.08 (实例访问到了更新后的类属性)
# 4. 再次支付 (使用新费率)
payment.pay(amount)
# 输出: 支付了 1080.0元
print(amount)
运行结果: