python中@property注解的具体使用

 更新时间:2025年12月26日 09:10:14   作者:大、男人  
property是 Python 内置的装饰器,用于将类的方法转换为属性式访问,本文就来详细的介绍一下@property注解的使用,感兴趣的可以了解一下

一、@property核心定义

@property 是 Python 内置的装饰器,用于将类的方法转换为属性式访问。它允许开发者将方法以属性的形式调用(如 obj.attr 而非 obj.attr()),同时封装属性的读取(getter)、赋值(setter)、删除(deleter)逻辑,实现受控的属性访问(如数据验证、计算属性、隐藏内部变量)。

核心价值:

  • 替代传统的 get_x()/set_x() 方法,让属性访问更直观、符合 Python 风格;
  • 兼顾封装性(隐藏内部变量)和易用性(属性式调用);
  • 支持动态计算属性(如根据其他属性推导值)、数据校验(如限制属性取值范围)。

二、基础用法

1. 只读属性(基础 getter)

最核心的用法是将方法转为只读属性,适用于「计算属性」(值由其他属性推导,无需手动赋值)。

示例:圆的面积计算

class Circle:
    def __init__(self, radius: float):
        self.radius = radius  # 基础属性

    @property
    def area(self) -> float:
        """计算面积(只读属性),无需调用方法,直接访问"""
        return 3.1415926 * self.radius **2

# 使用:像访问普通属性一样调用,无需加 ()
c = Circle(5)
print(c.area)  # 输出:78.539815
# 尝试赋值会报错(只读属性)
# c.area = 100  # AttributeError: can't set attribute

2. 可写属性(setter 装饰器)

通过 @属性名.setter 装饰器定义赋值逻辑,实现属性的可控写入(如数据验证)。

示例:年龄属性的校验

class Person:
    def __init__(self, name: str, age: int):
        self.name = name
        self._age = age  # 下划线前缀:约定俗成的「私有变量」(Python 无真正私有)

    @property
    def age(self) -> int:
        """getter:读取年龄"""
        return self._age

    @age.setter
    def age(self, value: int):
        """setter:赋值时验证数据合法性"""
        # 类型校验
        if not isinstance(value, int):
            raise TypeError("年龄必须是整数")
        # 范围校验
        if value < 0 or value > 150:
            raise ValueError("年龄必须在 0-150 之间")
        self._age = value

# 使用:赋值时自动触发 setter 校验
p = Person("Alice", 20)
print(p.age)  # 20(触发 getter)
p.age = 25    # 合法赋值(触发 setter)
# p.age = "30"  # 触发 TypeError
# p.age = 200   # 触发 ValueError

3. 可删除属性(deleter 装饰器)

通过 @属性名.deleter 装饰器定义属性删除逻辑,适用于需要清理资源的场景。

示例:删除年龄属性

class Person:
    # (继承上面的 __init__、age getter/setter)
    @age.deleter
    def age(self):
        """deleter:删除属性时执行的逻辑"""
        print("删除年龄属性...")
        del self._age

# 使用:删除属性触发 deleter
p = Person("Bob", 30)
del p.age  # 输出:删除年龄属性...
# 此时访问 p.age 会报错(_age 已被删除)
# print(p.age)  # AttributeError: 'Person' object has no attribute '_age'

三、进阶用法

1. 与继承结合:重写父类的 property

子类可重写父类的 @property 及其 setter/deleter,实现个性化逻辑。

class Student(Person):
    @property
    def age(self):
        """重写 getter:添加学生年龄的额外提示"""
        print(f"学生 {self.name} 的年龄:")
        return super().age  # 调用父类的 getter

    @age.setter
    def age(self, value):
        """重写 setter:添加学生年龄的特殊校验"""
        if value < 6 or value > 30:
            raise ValueError("学生年龄应在 6-30 之间")
        super(Student, Student).age.fset(self, value)  # 调用父类的 setter

# 测试
s = Student("Charlie", 18)
print(s.age)  # 输出:学生 Charlie 的年龄:18
s.age = 35    # 触发 ValueError

2. 缓存昂贵的计算属性

对于计算耗时的属性(如大数据处理、网络请求),可结合 functools.lru_cache 缓存结果,避免重复计算。

import functools

class DataProcessor:
    def __init__(self, raw_data: list[int]):
        self.raw_data = raw_data

    @property
    @functools.lru_cache(maxsize=None)  # 缓存方法结果
    def processed_data(self) -> list[int]:
        """模拟昂贵的计算:仅首次调用时计算,后续直接返回缓存"""
        print("执行昂贵计算...")
        return [x * 2 + 1 for x in self.raw_data]

# 测试
dp = DataProcessor([1, 2, 3, 4])
print(dp.processed_data)  # 输出:执行昂贵计算... [3, 5, 7, 9]
print(dp.processed_data)  # 直接返回缓存,无打印

3. 手动创建 property 对象(非装饰器方式)

@property 本质是语法糖,底层通过 property() 类实现。可手动创建 property 对象,效果与装饰器一致:

class Person:
    def __init__(self, age: int):
        self._age = age

    # 定义 getter/setter/deleter 方法
    def get_age(self):
        return self._age

    def set_age(self, value):
        if value < 0:
            raise ValueError("年龄不能为负")
        self._age = value

    def del_age(self):
        del self._age

    # 手动创建 property 对象:property(fget, fset, fdel, doc)
    age = property(get_age, set_age, del_age, "年龄属性,支持校验")

# 使用方式与装饰器一致
p = Person(20)
print(p.age)  # 20
p.age = 25    # 合法

四、关键注意事项

1. 命名规范:避免变量名冲突

  • 内部存储的变量建议用下划线前缀(如 _age),与 @property 装饰的方法名(如 age)区分,避免无限递归:
    # 错误示例:无限递归
    class Person:
        def __init__(self, age):
            self.age = age  # 赋值时触发 setter,setter 又赋值 self.age → 递归
    
        @property
        def age(self):
            return self.age  # 读取时触发 getter,getter 又读取 self.age → 递归
    
    # 正确:内部变量用 _age,property 方法用 age
    

2. 只读属性的限制

仅定义 @property(无 setter)的属性是只读的,尝试赋值会抛出 AttributeError,适合纯计算属性。

五、@propertyvs 传统 getter/setter

特性@property传统 get_x()/set_x()
调用方式obj.age(属性式)obj.get_age()(方法式)
封装性隐藏内部变量(如 _age)需手动约定命名规范
数据校验赋值时自动触发 setter 校验需手动调用 set_x() 校验
代码可读性更简洁、符合 Python 风格冗余、不够直观
兼容性仅新式类支持(Python 3 默认)全版本兼容

六、适用场景总结

场景推荐用法
计算属性(如面积、总价)仅定义 @property(只读)
需要数据校验的属性定义 @property + @属性名.setter
需要清理资源的属性额外定义 @属性名.deleter
封装内部变量,对外提供统一访问接口@property 替代手动 getter/setter
复用属性逻辑(多类共用)自定义描述符(而非 @property)

七、总结

@property 是 Python 面向对象编程中实现属性封装的核心工具,它以简洁的语法糖封装了描述符协议,兼顾了「易用性」(属性式访问)和「封装性」(受控的读写逻辑)。无论是实现计算属性、数据校验,还是隐藏内部变量,@property 都是比传统 getter/setter 更优雅的选择,是 Python 开发者必须掌握的特性之一。

到此这篇关于python中@property注解的具体使用的文章就介绍到这了,更多相关python @property注解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 解决Django模板无法使用perms变量问题的方法

    解决Django模板无法使用perms变量问题的方法

    这篇文章主要给大家介绍了关于解决Django模板无法使用perms变量问题的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2017-09-09
  • 教你在Excel中调用Python脚本实现数据自动化处理的方法

    教你在Excel中调用Python脚本实现数据自动化处理的方法

    Excel是全世界最流行的编程语言,Excel已经可以实现编程语言的算法,因此它是具备图灵完备性的,和JavaScript、Java、Python一样,今天通过本文给大家介绍下Python数据自动化处理的相关知识,感兴趣的朋友一起看看吧
    2022-02-02
  • Numpy之random函数使用学习

    Numpy之random函数使用学习

    这篇文章主要介绍了Numpy之random使用学习,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-01-01
  • Python数据类型探索列表魔法世界

    Python数据类型探索列表魔法世界

    这篇文章主要为大家介绍了Python数据类型探索列表魔法世界,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • python代码打包到exe的实现示例

    python代码打包到exe的实现示例

    本文主要介绍了python代码打包到exe的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-11-11
  • 解决python 输出到csv 出现多空行的情况

    解决python 输出到csv 出现多空行的情况

    这篇文章主要介绍了解决python 输出到csv 出现多空行的情况,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-03-03
  • windows+vscode安装paddleOCR运行环境的步骤

    windows+vscode安装paddleOCR运行环境的步骤

    这篇文章主要介绍了windows+vscode安装paddleOCR运行环境,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11
  • Python中处理表格数据的Tablib库详解

    Python中处理表格数据的Tablib库详解

    这篇文章主要介绍了Python中处理表格数据的Tablib库详解,Tablib 是一个 MIT 许可的格式不可知的表格数据集库,用 Python 编写,它允许您导入、导出和操作表格数据集,需要的朋友可以参考下
    2023-08-08
  • Python关于时间序列calendar模块的深入讲解

    Python关于时间序列calendar模块的深入讲解

    calendar,是与日历相关的模块。calendar模块文件里定义了很多类型,主要有Calendar,TextCalendar以及HTMLCalendar类型。其中,Calendar是TextCalendar与HTMLCalendar的基类
    2021-11-11
  • Python线性表种的单链表详解

    Python线性表种的单链表详解

    这篇文章主要介绍了Python线性表种的单链表详解,线性表是一种线性结构,它是由零个或多个数据元素构成的有限序列。线性表的特征是在一个序列中,除了头尾元素,每个元素都有且只有一个直接前驱,有且只有一个直接后继
    2022-08-08

最新评论