@property 装饰器是 Python 中实现属性访问控制的强大工具,它允许你将方法转换为"动态属性",提供更精细的属性访问控制。
在面向对象编程中,直接暴露类的属性存在以下问题:
- 无法验证数据:无法在赋值时检查数据有效性
- 无法动态计算:属性值不能基于其他属性动态计算
- 破坏封装性:外部可直接修改内部状态
@property 解决了这些问题,让你能够:
class MyClass:
    def__init__(self, value):
        self._value = value  # 内部使用带下划线的变量名
    
    @property
    defvalue(self):
        """Getter方法:访问属性时调用"""
        returnself._value
    
    @value.setter
    defvalue(self, new_value):
        """Setter方法:设置属性时调用"""
        if new_value < 0:
            raise ValueError("值不能为负数")
        self._value = new_value
    
    @value.deleter
    defvalue(self):
        """Deleter方法:删除属性时调用"""
        print("删除值!")
        delself._value
1. 只读属性(无 setter)
class Circle:
    def__init__(self, radius):
        self.radius = radius
    
    @property
    defarea(self):
        """只读属性:计算圆的面积"""
        return3.14 * self.radius ** 2
# 使用
c = Circle(5)
print(c.area)  # 78.5
c.area = 100# 报错:AttributeError: can't set attribute
2. 数据验证
class Temperature:
    def__init__(self, celsius):
        self.celsius = celsius  # 使用setter
    
    @property
    defcelsius(self):
        returnself._celsius
    
    @celsius.setter
    defcelsius(self, value):
        if value < -273.15:
            raise ValueError("温度不能低于绝对零度")
        self._celsius = value
# 使用
temp = Temperature(25)
temp.celsius = -300# ValueError: 温度不能低于绝对零度
3. 属性别名
class Person:
    def__init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name
    
    @property
    deffull_name(self):
        """动态计算全名"""
        returnf"{self.first_name} {self.last_name}"
    
    @full_name.setter
    deffull_name(self, name):
        """通过全名设置姓名"""
        first, last = name.split(" ", 1)
        self.first_name = first
        self.last_name = last
# 使用
p = Person("张", "三")
print(p.full_name)  # 张 三
p.full_name = "李 四"
print(p.first_name)  # 李
1. 属性缓存
class ExpensiveCalculation:
    def__init__(self):
        self._result = None
    
    @property
    defresult(self):
        """缓存计算结果"""
        ifself._result isNone:
            print("执行复杂计算...")
            self._result = self._calculate()
        returnself._result
    
    def_calculate(self):
        # 模拟复杂计算
        returnsum(range(1, 1000000))
# 使用
calc = ExpensiveCalculation()
print(calc.result)  # 第一次调用会计算
print(calc.result)  # 直接返回缓存结果
2. 属性依赖
class Rectangle:
    def__init__(self, width, height):
        self.width = width
        self.height = height
    
    @property
    defarea(self):
        returnself.width * self.height
    
    @property
    defperimeter(self):
        return2 * (self.width + self.height)
    
    @property
    defaspect_ratio(self):
        """宽高比(只读)"""
        returnself.width / self.height
    
    @aspect_ratio.setter
    defaspect_ratio(self, ratio):
        """通过宽高比设置尺寸,保持面积不变"""
        current_area = self.area
        self.width = (current_area * ratio) ** 0.5
        self.height = current_area / self.width
# 使用
rect = Rectangle(4, 3)
print(f"原始尺寸: {rect.width}x{rect.height}")  # 4x3
rect.aspect_ratio = 16/9
print(f"新尺寸: {rect.width:.1f}x{rect.height:.1f}")  # 6.5x3.7
- 命名规范: 
- 性能考虑: 
- 何时使用: 
- 常见错误: - class BadExample:
 @property
 def value(self):
 return self.value  # 递归调用自身!
 
 @value.setter
 def value(self, new_value):
 self.value = new_value  # 递归设置!
 
 - 正确做法:使用带下划线的内部变量 
- 与普通属性的区别: 
选择建议:
配置管理系统
class AppConfig:
    def__init__(self):
        self._settings = {}
        self._cache = {}
    
    @property
    deftheme(self):
        """获取当前主题"""
        returnself._settings.get('theme', 'light')
    
    @theme.setter
    deftheme(self, value):
        """设置主题并验证"""
        if value notin ['light', 'dark', 'system']:
            raise ValueError("无效的主题选项")
        self._settings['theme'] = value
        self._cache.clear()  # 清除缓存
    
    @property
    defapi_endpoint(self):
        """动态构建API端点"""
        if'api_endpoint'notinself._cache:
            base_url = self._settings.get('base_url', 'https://api.example.com')
            version = self._settings.get('api_version', 'v1')
            self._cache['api_endpoint'] = f"{base_url}/{version}/"
        returnself._cache['api_endpoint']
# 使用
config = AppConfig()
config.theme = 'dark'
print(config.theme)  # dark
print(config.api_endpoint)  # https://api.example.com/v1/
@property 装饰器是 Python 面向对象编程中不可或缺的工具:
关键要点:
- 使用 @property定义 getter 方法
- 使用 @x.setter定义 setter 方法
- 使用 @x.deleter定义 deleter 方法
掌握 @property 更加 Pythonic地设计类,在保持接口简洁的同时实现强大的属性控制功能。
阅读原文:原文链接
该文章在 2025/7/18 10:34:59 编辑过