器→工具, 编程语言

Python @property 装饰器详解

钱魏Way · · 126 次浏览

@property 装饰器简介

在 Python 中,@property 装饰器是一种优雅的属性管理工具,它允许你将类的方法伪装成属性(即无需使用 () 调用),同时可以在属性访问时添加逻辑(如数据校验、动态计算等)。

@property 的核心作用

  • 隐藏实现细节:对外暴露属性式的访问接口,内部可封装复杂逻辑。
  • 控制属性访问:在读取、设置或删除属性时触发自定义逻辑(如数据校验)。
  • 兼容性:允许在不破坏现有代码的前提下修改内部实现。

基本用法:定义属性的读写删除

定义属性的读取(getter)

使用 @property 装饰器将一个方法转换为“属性读取”方法:

class Person:
    def __init__(self, name):
        self._name = name  # 实际存储的属性(通常用下划线命名)

    @property
    def name(self):
        print("Getting name")
        return self._name

# 使用
p = Person("Alice")
print(p.name)  # 输出: Getting name → Alice

定义属性的设置(setter)

使用 @属性名.setter 装饰器定义属性的设置逻辑:

class Person:
    def __init__(self, name):
        self._name = name

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        if not isinstance(value, str):
            raise ValueError("Name must be a string!")
        print("Setting name")
        self._name = value

# 使用
p = Person("Alice")
p.name = "Bob"    # 正常设置
p.name = 123      # 抛出 ValueError

定义属性的删除(deleter)

使用 @属性名.deleter 装饰器定义删除逻辑:

class Person:
    def __init__(self, name):
        self._name = name

    @property
    def name(self):
        return self._name

    @name.deleter
    def name(self):
        print("Deleting name")
        del self._name

# 使用
p = Person("Alice")
del p.name  # 输出: Deleting name

典型应用场景

数据校验

禁止非法值被设置:

class Circle:
    def __init__(self, radius):
        self.radius = radius  # 通过 setter 设置

    @property
    def radius(self):
        return self._radius

    @radius.setter
    def radius(self, value):
        if value <= 0:
            raise ValueError("Radius must be positive")
        self._radius = value

动态计算属性

属性值由其他属性动态计算得出:

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height

    @property
    def area(self):
        return self.width * self.height  # 每次访问时计算

# 使用
rect = Rectangle(3, 4)
print(rect.area)  # 输出: 12
rect.width = 5
print(rect.area)  # 输出: 20 (自动更新)

属性访问控制

限制某些属性为只读:

class User:
    def __init__(self, user_id):
        self._user_id = user_id

    @property
    def user_id(self):
        return self._user_id  # 无 setter,无法修改

# 使用
user = User(1001)
user.user_id = 2002  # 抛出 AttributeError: can't set attribute

深入原理

  • 属性本质:@property创建了一个 property 对象,管理属性的 get、set、delete 方法。
  • 描述符协议:property实现了描述符协议,通过 __get__、__set__ 和 __delete__ 方法拦截属性操作。

注意事项

  • 避免副作用:Getter 方法尽量不修改对象状态。
  • 性能考量:频繁计算的属性可考虑缓存结果。
  • 命名冲突:属性名不要与实例变量同名(如用_name 存储数据,name 作为属性)。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注