Python @property

本文介绍如何使用Python的@property装饰器实现对类属性的有效性和访问控制,通过实例演示如何避免直接修改属性带来的问题。

考察 Student 类:

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score

当我们想要修改一个 Student 的 scroe 属性时,可以这么写:

s = Student('Bob', 59)
s.score = 60
但是也可以这么写:

s.score = 1000

显然,直接给属性赋值无法检查分数的有效性。

如果利用两个方法:

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.__score = score
    def get_score(self):
        return self.__score
    def set_score(self, score):
        if score < 0 or score > 100:
            raise ValueError('invalid score')
        self.__score = score

这样一来,s.set_score(1000) 就会报错。

这种使用 get/set 方法来封装对一个属性的访问在许多面向对象编程的语言中都很常见。

但是写 s.get_score() 和 s.set_score() 没有直接写 s.score 来得直接。

有没有两全其美的方法?----有。

因为Python支持高阶函数,在函数式编程中我们介绍了装饰器函数,可以用装饰器函数把 get/set 方法“装饰”成属性调用:

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.__score = score
    @property
    def score(self):
        return self.__score
    @score.setter
    def score(self, score):
        if score < 0 or score > 100:
            raise ValueError('invalid score')
        self.__score = score

注意: 第一个score(self)是get方法,用@property装饰,第二个score(self, score)是set方法,用@score.setter装饰,@score.setter是前一个@property装饰后的副产品。

现在,就可以像使用属性一样设置score了:

>>> s = Student('Bob', 59)
>>> s.score = 60
>>> print s.score
60
>>> s.score = 1000
Traceback (most recent call last):
  ...
ValueError: invalid score

说明对 score 赋值实际调用的是 set方法

<think>我们被要求回答关于Python@property装饰器的使用和原理。根据提供的引用材料,我们可以总结出以下信息: 1. @property装饰器允许将类的方法转换为属性,这样我们可以像访问属性一样访问方法,而不需要在调用时加上括号。 2. 它通常用于封装属性,添加验证逻辑,以及实现属性的惰性计算等。 3. 通过使用@property,我们可以定义getter方法;同时,还可以使用@<property_name>.setter来定义setter方法,以及@<property_name>.deleter来定义删除属性的方法。 4. 使用@property可以提高代码的可读性和可维护性,同时确保数据的安全性(例如,可以在setter中添加验证)。 根据这些信息,我们可以组织回答如下: ### 回答结构: 1. 介绍@property装饰器的作用和基本用法。 2. 解释如何使用@property定义getter、setter和deleter。 3. 举例说明@property的应用场景和优势。 4. 简要说明其实现原理(基于描述符协议)。 ### 注意: - 由于要求使用中文回答,且行内数学表达式需要用$...$,但本题不涉及数学公式,因此重点在代码和文字说明。 - 独立代码块使用三个反引号包裹,并指定语言为python。 - 在回答末尾生成相关问题。 下面开始回答: </think> ### Python @property装饰器的使用与原理 #### 1. **基本作用与核心功能** `@property`装饰器可将类方法转换为“属性式访问”,实现**数据封装**与**访问控制**: - 将方法调用转为类似属性访问的形式:`obj.value` 替代 `obj.value()` - 通过配套的 setter/deleter 实现属性赋值和删除的逻辑控制 - 典型应用场景: - 数据验证(如类型/范围检查) - 惰性计算(延迟加载) - 访问权限控制 - 保持API兼容性(修改内部逻辑不影响外部调用)[^1][^3] #### 2. **使用方法详解** ```python class Circle: def __init__(self, radius): self._radius = radius # 实际存储私有变量 @property def radius(self): """Getter:访问时自动调用""" print("获取半径") return self._radius @radius.setter def radius(self, value): """Setter:赋值时触发验证""" if value <= 0: raise ValueError("半径必须为正数") print("设置半径") self._radius = value @radius.deleter def radius(self): """Deleter:删除属性时调用""" print("删除半径") del self._radius @property def area(self): """计算属性:无setter时为只读属性""" return 3.14 * self._radius ** 2 # 使用示例 c = Circle(5) print(c.radius) # 输出: 获取半径 → 5 c.radius = 10 # 输出: 设置半径 print(c.area) # 输出: 314.0 (只读属性) del c.radius # 输出: 删除半径 ``` #### 3. **实现原理** 底层基于**描述符协议**(Descriptor Protocol): 1. `@property` 创建实现了 `__get__()` 方法的描述符对象 2. `@x.setter` 和 `@x.deleter` 分别扩展描述符的 `__set__()` 和 `__delete__()` 方法 3. 当访问属性时,Python自动触发对应描述符方法[^2][^4] > 本质转化: > ```python > class Property: > def __get__(self, obj, objtype=None): > return obj.getter_method() > def __set__(self, obj, value): > obj.setter_method(value) > ``` #### 4. **优势与典型场景** | **优势** | **应用示例** | |--------------------|----------------------------------| | **数据验证** | 属性赋值时检查数据类型/范围 | | **动态计算** | 属性访问时实时计算(如面积、汇率)| | **接口兼容** | 内部变量名变更不影响外部调用 | | **访问控制** | 实现只读/只写属性 | | **延迟加载** | 首次访问时加载大数据资源 | 例如金融类中保证金额非负: ```python class Account: @property def balance(self): return self._balance @balance.setter def balance(self, value): if value < 0: raise ValueError("余额不能为负") self._balance = value ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值