精通 Python @property 装饰器:简洁、向后兼容的 Getter 与 Setter
精通 Python @property 装饰器
了解 Python 内置 @property 装饰器如何让你编写简洁、可维护的 getter 和 setter,同时保持 API 向后兼容。
Python 的 @property 装饰器是封装属性访问的强大工具。它让你定义属性读写时运行的自定义逻辑,而无需强制调用者修改代码。以下章节将通过真实案例——处理温度转换——演示如何强制约束,并解释为何 @property 是地道解决方案。
无 Getter/Setter 的类
假设需要一个简单类存储摄氏温度并能转华氏度:
class Celsius:
def __init__(self, temperature=0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
使用很简单:
# 创建新对象
human = Celsius()
# 设置温度
human.temperature = 37
# 读取温度
print(human.temperature)
# 转华氏度
print(human.to_fahrenheit())
输出
37 98.60000000000001
浮点结果因十进制二进制表示预期。查看 human.__dict__ 可见 Python 在普通字典条目存储值:
>>> human.__dict__
{'temperature': 37}
用 Getter/Setter 添加约束
真实对象常需验证。如温度不能低于绝对零度(-273.15 °C)。直接方式是隐藏属性并暴露显式 getter/setter:
class Celsius:
def __init__(self, temperature=0):
self.set_temperature(temperature)
def to_fahrenheit(self):
return (self.get_temperature() * 1.8) + 32
# getter
def get_temperature(self):
return self._temperature
# setter
def set_temperature(self, value):
if value < -273.15:
raise ValueError("Temperature below -273.15 is not possible.")
self._temperature = value
类虽强制下界,但现有代码访问 obj.temperature 必须改为 obj.get_temperature() 和 obj.set_temperature(val)。大型代码库这意味着大规模重构。
且 Python “私有”变量仅是命名约定——_temperature 仍可直接访问,破坏封装。@property 正是解决此问题。
使用 property 类
Python 提供 property 类将 getter/setter 函数绑定到属性名:
class Celsius:
def __init__(self, temperature=0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
# getter
def get_temperature(self):
print("Getting value...")
return self._temperature
# setter
def set_temperature(self, value):
print("Setting value...")
if value < -273.15:
raise ValueError("Temperature below -273.15 is not possible")
self._temperature = value
# 暴露为 property
temperature = property(get_temperature, set_temperature)
此设置下,以下代码行为与原简单类完全一致,但背后有验证:
human = Celsius(37)
print(human.temperature) # 触发 getter
print(human.to_fahrenheit()) # 内部用 getter
human.temperature = -300 # 触发 setter 并引发 ValueError
输出
Setting value... Getting value... 37 Getting value... 98.60000000000001 Setting value... Traceback (most recent call last): ... ValueError: Temperature below -273 is not possible
注意访问 temperature 的代码未变;仅底层实现获得验证。
提示:实际数据存在 _temperature;temperature 只是方便安全的接口。
@property 装饰器
property 类虽可用,但 Python 装饰器语法提供更清晰、可读的方式达成同等效果。装饰器自动创建 property 对象并将 getter/setter 绑定到属性名。
class Celsius:
def __init__(self, temperature=0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
@property
def temperature(self):
print("Getting value...")
return self._temperature
@temperature.setter
def temperature(self, value):
print("Setting value...")
if value < -273.15:
raise ValueError("Temperature below -273 is not possible")
self._temperature = value
用法保持不变:
human = Celsius(37)
print(human.temperature)
print(human.to_fahrenheit())
# 尝试设置无效温度
try:
Celsius(-300)
except ValueError as e:
print(e)
输出
Setting value... Getting value... 37 Getting value... 98.60000000000001 Setting value... Traceback (most recent call last): ... ValueError: Temperature below -273 is not possible
使用 @property 保持命名空间整洁,免去单独 getter/setter 方法名,是大多数 Python 开发者的推荐模式。
Python
- 精通Python数据类型:实战指南
- 精通Python运算符:全面指南
- 精通Python Pass语句:实战指南
- 精通Python函数参数:位置、关键字与默认参数
- 精通 Python 字典:创建、操作与进阶技巧
- 精通 Python 继承:概念、语法与实战示例
- 精通 Python 运算符重载:实战指南
- 精通 Python 迭代器:工作原理与自定义构建
- Python 闭包详解:嵌套函数如何捕获变量
- 精通 Python @property 装饰器:简洁、向后兼容的 Getter 与 Setter
- 精通 Python datetime:日期、时间与时区实战指南
- 精通 Python time.sleep():最佳实践、多线程与实战案例