Python进阶--@property详解
·
property 是 Python 中用于管理类属性访问的核心工具,它能将类的方法“伪装”成属性,在保持代码简洁性的同时,实现属性的封装、验证、计算等高级功能。
一、property 的核心作用
1. 封装内部实现
隐藏属性的具体操作逻辑(如数据存储方式、计算过程),仅对外暴露简洁的属性访问接口。
2. 数据验证与保护
在设置属性值时自动执行验证逻辑(如范围检查、类型校验),防止非法数据破坏对象状态。
3. 动态计算属性值
根据其他属性动态计算结果(无需额外存储),确保数据一致性。
4. 向后兼容
当类的内部实现变更时(如将直接属性访问改为方法调用),无需修改外部代码。
二、property 的两种用法
用法 1:@property 装饰器(推荐,更简洁)
通过装饰器将方法转换为属性,分为 getter(读取)、setter(设置)、deleter(删除)三个部分。
语法结构
class MyClass:
@property
def my_attr(self):
# getter:读取属性时调用
return self._my_attr # 通常用下划线开头表示内部属性
@my_attr.setter
def my_attr(self, value):
# setter:设置属性时调用(可选)
# 可在此添加验证逻辑
self._my_attr = value
@my_attr.deleter
def my_attr(self):
# deleter:删除属性时调用(可选)
del self._my_attr
完整案例:学生成绩管理系统
class Student:
def __init__(self, name, score):
self.name = name # 普通属性
self.score = score # 受 property 管理的属性
# ------------------------------
# 1. score 属性的 getter(读取)
# ------------------------------
@property
def score(self):
"""获取学生成绩(自动返回内部存储的 _score)"""
return self._score
# ------------------------------
# 2. score 属性的 setter(设置,含验证)
# ------------------------------
@score.setter
def score(self, value):
"""设置学生成绩(必须在 0-100 之间)"""
# 数据验证:类型检查
if not isinstance(value, (int, float)):
raise TypeError("成绩必须是数字(int 或 float)")
# 数据验证:范围检查
if not (0 <= value <= 100):
raise ValueError("成绩必须在 0-100 之间")
# 验证通过后,存储到内部属性 _score
self._score = value
# ------------------------------
# 3. 动态计算属性:grade(根据 score 自动计算等级)
# ------------------------------
@property
def grade(self):
"""根据成绩动态返回等级(A/B/C/D/F)"""
if self._score >= 90:
return "A"
elif self._score >= 80:
return "B"
elif self._score >= 70:
return "C"
elif self._score >= 60:
return "D"
else:
return "F"
# ------------------------------
# 4. deleter:删除 score 时的清理逻辑
# ------------------------------
@score.deleter
def score(self):
"""删除成绩时的提示(可选)"""
print(f"已删除学生 {self.name} 的成绩")
del self._score
# ------------------------------
# 测试案例
# ------------------------------
if __name__ == "__main__":
# 1. 创建学生对象(合法成绩)
try:
student = Student("张三", 85)
print(f"姓名:{student.name}")
print(f"成绩:{student.score}") # 像访问属性一样调用 getter
print(f"等级:{student.grade}") # 动态计算的属性
except (TypeError, ValueError) as e:
print(f"初始化失败:{e}")
# 输出:
# 姓名:张三
# 成绩:85
# 等级:B
# 2. 尝试设置非法成绩(验证逻辑生效)
try:
student.score = 105 # 超出范围
except ValueError as e:
print(f"设置失败:{e}") # 输出:设置失败:成绩必须在 0-100 之间
try:
student.score = "优秀" # 类型错误
except TypeError as e:
print(f"设置失败:{e}") # 输出:设置失败:成绩必须是数字(int 或 float)
# 3. 修改成绩后,等级自动更新
student.score = 92
print(f"\n修改后成绩:{student.score}")
print(f"修改后等级:{student.grade}") # 输出:A
# 4. 删除成绩(触发 deleter)
del student.score # 输出:已删除学生 张三 的成绩
用法 2:property() 函数(传统方式)
通过内置函数 property() 直接创建属性对象,语法为:
property(fget=None, fset=None, fdel=None, doc=None)
fget:获取属性的方法(getter)fset:设置属性的方法(setter)fdel:删除属性的方法(deleter)doc:属性的文档字符串
案例:用 property() 重写学生类
class Student:
def __init__(self, name, score):
self.name = name
self._score = None # 内部存储的属性
self.score = score # 通过 setter 初始化
# getter 方法
def _get_score(self):
return self._score
# setter 方法(含验证)
def _set_score(self, value):
if not isinstance(value, (int, float)):
raise TypeError("成绩必须是数字")
if not (0 <= value <= 100):
raise ValueError("成绩必须在 0-100 之间")
self._score = value
# deleter 方法
def _del_score(self):
print(f"已删除 {self.name} 的成绩")
del self._score
# 动态计算 grade 的方法
def _get_grade(self):
if self._score >= 90:
return "A"
elif self._score >= 80:
return "B"
# ... 省略其他等级逻辑
else:
return "F"
# ------------------------------
# 使用 property() 创建属性
# ------------------------------
score = property(
fget=_get_score,
fset=_set_score,
fdel=_del_score,
doc="学生成绩(0-100)"
)
grade = property(fget=_get_grade) # 只读属性(无 setter)
# 测试(与装饰器方式效果一致)
student = Student("李四", 78)
print(student.score) # 78
print(student.grade) # C
三、关键注意事项
1. 内部属性命名规范
通常用单下划线(如 _score)表示“内部使用的属性”,提醒外部代码不要直接访问(但 Python 不会强制禁止)。
2. 只读属性的实现
如果只定义 getter 而不定义 setter,属性将变为只读,尝试修改会抛出 AttributeError:
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius # 只有 getter,无 setter
c = Circle(5)
print(c.radius) # 5
# c.radius = 10 # 报错:AttributeError: can't set attribute
3. 避免无限递归
如果在 getter/setter 中直接访问属性本身(而非内部属性),会导致无限递归:
# 错误示例!
class BadExample:
@property
def value(self):
return self.value # 无限递归调用 getter!
@value.setter
def value(self, v):
self.value = v # 无限递归调用 setter!
解决方法:始终用内部属性(如 _value)存储数据。
四、总结
- 推荐使用
@property装饰器:代码更简洁、可读性更强,符合 Python 风格。 - 核心场景:数据验证、动态计算属性、封装内部逻辑。
- 命名规范:内部属性用单下划线前缀,避免与
property属性冲突。
通过 property,你可以在保持接口简洁的同时,为属性添加强大的管理逻辑,是 Python 面向对象编程中不可或缺的工具!
更多推荐



所有评论(0)