Python黑科技:用@property优雅管理你的属性访问
一、property的前世今生
property本质上是一个类(划重点!),它的完整构造方法如下:
property(fget=None, fset=None, fdel=None, doc=None)
历史小知识📜:
- Python 2.2引入property类型
- Python 2.4才出现@装饰器语法
- 早期只能这样使用:
weight = property(get_weight, set_weight)
二、新旧写法大比拼
经典写法(Python 2.2风格)
class LineItem:def get_weight(self): return self.__weightdef set_weight(self, value):if value > 0:self.__weight = valueelse:raise ValueError('必须>0')weight = property(get_weight, set_weight)
现代写法(装饰器版)
class LineItem:@property def weight(self):return self.__weight@weight.setterdef weight(self, value):if value > 0:self.__weight = valueelse:raise ValueError('必须>0')
优势对比💡:
✔️ 装饰器版更直观
✔️ 避免get/set前缀污染方法名
✔️ 代码组织结构更清晰
三、特性覆盖的玄机
property有个重要特性:类属性管理实例属性。来看几个关键现象:
1. 数据属性遮盖规则
obj.attr → 先找类属性,再找实例属性
2. 特性不可遮盖
即使手动在__dict__
中添加同名属性:
obj.__dict__['prop'] = 'foo' # 添加成功
obj.prop # 依然调用特性方法!
3. 动态修改特性
Class.prop = 'baz' # 销毁特性
obj.prop # 此时返回实例属性
四、如何添加文档说明
两种添加文档的方式:
1. 经典写法:
weight = property(get_weight, set_weight, doc='重量(kg)')
2. 装饰器写法(自动获取getter的docstring):
@property
def weight(self):"""重量(kg)"""return self.__weight
五、实战建议
1. 输入验证的最佳实践:
@price.setter
def price(self, value):if not isinstance(value, (int, float)):raise TypeError("需数字类型")if value <= 0:raise ValueError("必须>0")self.__price = value
2. 计算属性的优雅实现:
@property
def subtotal(self):return self.weight * self.price
3. 只读属性的创建技巧:
@property
def id(self):return self.__id # 不定义setter即成只读