python中@property注解的具体使用
作者:大、男人
一、@property核心定义
@property 是 Python 内置的装饰器,用于将类的方法转换为属性式访问。它允许开发者将方法以属性的形式调用(如 obj.attr 而非 obj.attr()),同时封装属性的读取(getter)、赋值(setter)、删除(deleter)逻辑,实现受控的属性访问(如数据验证、计算属性、隐藏内部变量)。
核心价值:
- 替代传统的
get_x()/set_x()方法,让属性访问更直观、符合 Python 风格; - 兼顾封装性(隐藏内部变量)和易用性(属性式调用);
- 支持动态计算属性(如根据其他属性推导值)、数据校验(如限制属性取值范围)。
二、基础用法
1. 只读属性(基础 getter)
最核心的用法是将方法转为只读属性,适用于「计算属性」(值由其他属性推导,无需手动赋值)。
示例:圆的面积计算
class Circle:
def __init__(self, radius: float):
self.radius = radius # 基础属性
@property
def area(self) -> float:
"""计算面积(只读属性),无需调用方法,直接访问"""
return 3.1415926 * self.radius **2
# 使用:像访问普通属性一样调用,无需加 ()
c = Circle(5)
print(c.area) # 输出:78.539815
# 尝试赋值会报错(只读属性)
# c.area = 100 # AttributeError: can't set attribute
2. 可写属性(setter 装饰器)
通过 @属性名.setter 装饰器定义赋值逻辑,实现属性的可控写入(如数据验证)。
示例:年龄属性的校验
class Person:
def __init__(self, name: str, age: int):
self.name = name
self._age = age # 下划线前缀:约定俗成的「私有变量」(Python 无真正私有)
@property
def age(self) -> int:
"""getter:读取年龄"""
return self._age
@age.setter
def age(self, value: int):
"""setter:赋值时验证数据合法性"""
# 类型校验
if not isinstance(value, int):
raise TypeError("年龄必须是整数")
# 范围校验
if value < 0 or value > 150:
raise ValueError("年龄必须在 0-150 之间")
self._age = value
# 使用:赋值时自动触发 setter 校验
p = Person("Alice", 20)
print(p.age) # 20(触发 getter)
p.age = 25 # 合法赋值(触发 setter)
# p.age = "30" # 触发 TypeError
# p.age = 200 # 触发 ValueError
3. 可删除属性(deleter 装饰器)
通过 @属性名.deleter 装饰器定义属性删除逻辑,适用于需要清理资源的场景。
示例:删除年龄属性
class Person:
# (继承上面的 __init__、age getter/setter)
@age.deleter
def age(self):
"""deleter:删除属性时执行的逻辑"""
print("删除年龄属性...")
del self._age
# 使用:删除属性触发 deleter
p = Person("Bob", 30)
del p.age # 输出:删除年龄属性...
# 此时访问 p.age 会报错(_age 已被删除)
# print(p.age) # AttributeError: 'Person' object has no attribute '_age'
三、进阶用法
1. 与继承结合:重写父类的 property
子类可重写父类的 @property 及其 setter/deleter,实现个性化逻辑。
class Student(Person):
@property
def age(self):
"""重写 getter:添加学生年龄的额外提示"""
print(f"学生 {self.name} 的年龄:")
return super().age # 调用父类的 getter
@age.setter
def age(self, value):
"""重写 setter:添加学生年龄的特殊校验"""
if value < 6 or value > 30:
raise ValueError("学生年龄应在 6-30 之间")
super(Student, Student).age.fset(self, value) # 调用父类的 setter
# 测试
s = Student("Charlie", 18)
print(s.age) # 输出:学生 Charlie 的年龄:18
s.age = 35 # 触发 ValueError
2. 缓存昂贵的计算属性
对于计算耗时的属性(如大数据处理、网络请求),可结合 functools.lru_cache 缓存结果,避免重复计算。
import functools
class DataProcessor:
def __init__(self, raw_data: list[int]):
self.raw_data = raw_data
@property
@functools.lru_cache(maxsize=None) # 缓存方法结果
def processed_data(self) -> list[int]:
"""模拟昂贵的计算:仅首次调用时计算,后续直接返回缓存"""
print("执行昂贵计算...")
return [x * 2 + 1 for x in self.raw_data]
# 测试
dp = DataProcessor([1, 2, 3, 4])
print(dp.processed_data) # 输出:执行昂贵计算... [3, 5, 7, 9]
print(dp.processed_data) # 直接返回缓存,无打印
3. 手动创建 property 对象(非装饰器方式)
@property 本质是语法糖,底层通过 property() 类实现。可手动创建 property 对象,效果与装饰器一致:
class Person:
def __init__(self, age: int):
self._age = age
# 定义 getter/setter/deleter 方法
def get_age(self):
return self._age
def set_age(self, value):
if value < 0:
raise ValueError("年龄不能为负")
self._age = value
def del_age(self):
del self._age
# 手动创建 property 对象:property(fget, fset, fdel, doc)
age = property(get_age, set_age, del_age, "年龄属性,支持校验")
# 使用方式与装饰器一致
p = Person(20)
print(p.age) # 20
p.age = 25 # 合法
四、关键注意事项
1. 命名规范:避免变量名冲突
- 内部存储的变量建议用下划线前缀(如
_age),与@property装饰的方法名(如age)区分,避免无限递归:# 错误示例:无限递归 class Person: def __init__(self, age): self.age = age # 赋值时触发 setter,setter 又赋值 self.age → 递归 @property def age(self): return self.age # 读取时触发 getter,getter 又读取 self.age → 递归 # 正确:内部变量用 _age,property 方法用 age
2. 只读属性的限制
仅定义 @property(无 setter)的属性是只读的,尝试赋值会抛出 AttributeError,适合纯计算属性。
五、@propertyvs 传统 getter/setter
| 特性 | @property | 传统 get_x()/set_x() |
|---|---|---|
| 调用方式 | obj.age(属性式) | obj.get_age()(方法式) |
| 封装性 | 隐藏内部变量(如 _age) | 需手动约定命名规范 |
| 数据校验 | 赋值时自动触发 setter 校验 | 需手动调用 set_x() 校验 |
| 代码可读性 | 更简洁、符合 Python 风格 | 冗余、不够直观 |
| 兼容性 | 仅新式类支持(Python 3 默认) | 全版本兼容 |
六、适用场景总结
| 场景 | 推荐用法 |
|---|---|
| 计算属性(如面积、总价) | 仅定义 @property(只读) |
| 需要数据校验的属性 | 定义 @property + @属性名.setter |
| 需要清理资源的属性 | 额外定义 @属性名.deleter |
| 封装内部变量,对外提供统一访问接口 | @property 替代手动 getter/setter |
| 复用属性逻辑(多类共用) | 自定义描述符(而非 @property) |
七、总结
@property 是 Python 面向对象编程中实现属性封装的核心工具,它以简洁的语法糖封装了描述符协议,兼顾了「易用性」(属性式访问)和「封装性」(受控的读写逻辑)。无论是实现计算属性、数据校验,还是隐藏内部变量,@property 都是比传统 getter/setter 更优雅的选择,是 Python 开发者必须掌握的特性之一。
到此这篇关于python中@property注解的具体使用的文章就介绍到这了,更多相关python @property注解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
您可能感兴趣的文章:
- python @property的用法及含义全面解析
- 介绍Python的@property装饰器的用法
- 实例讲解Python编程中@property装饰器的用法
- python 中的@property的用法详解
- Python 中@property的用法详解
- Python @property装饰器原理解析
- 详解Python装饰器之@property
- Python进阶之@property动态属性的实现
- python装饰器中@property属性的使用解析
- Python @property原理解析和用法实例
- Python如何使用@property @x.setter及@x.deleter
- Python @property使用方法解析
- python中@Property属性使用方法
