装饰器 · property

0. 一句话定位

维度 内容
作用对象 类实例方法
使用场景 属性访问
来源 标准库 builtins.property
语法形式 @property;可选 @name.setter / @name.deleter

段末注释:描述符(descriptor) 协议中,property 把方法包装成 obj.attr 形式的访问接口。

1. 做什么

obj.method() 变为 obj.method 的属性访问;可在 setter 中校验或转换,用 _field 存真实数据,对外隐藏内部字段名。

2. 重点参数

参数 类型 默认值 作用 配置建议
fget callable 读取时调用 通常 @property 装饰方法,不显式传
fset callable None 写入时调用 @x.setter 定义;不设则只读
fdel callable None del obj.x 时调用 少见;需 @x.deleter
doc str None 属性文档 默认继承 fget 的 __doc__

3. 最小可运行示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class DataSet:
def __init__(self):
self._images = 1
self._labels = 2

@property
def images(self):
return self._images

@property
def labels(self):
return self._labels

ds = DataSet()
print(ds.images) # 1,无需括号
print(ds.labels) # 2

带 setter 的完整示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class DataSet:
def __init__(self):
self._images = 1

@property
def images(self):
return self._images

@images.setter
def images(self, value):
if value < 0:
raise ValueError("images 不能为负")
self._images = value

ds = DataSet()
ds.images = 3
print(ds.images) # 3

4. 常见变体

  • 只读属性:仅 @property,不定义 setter
  • 计算属性:getter 内按需计算,不缓存(需缓存见 functools.cached_property
  • 与 deleter@images.deleter 配合 del obj.images

5. 适用 / 不适用

适用

  • 对外暴露字段,但需在读取/写入时做校验或惰性计算
  • 希望 API 用 obj.name 而非 obj.get_name()

不适用

  • 简单数据容器且无校验需求(直接用 __init__ 赋值即可)
  • 需要 @classmethod / @staticmethod 语义的方法(不能直接与 @property 叠在同一方法上)

6. 易踩坑

  • 只写 @property 无 setter 时赋值会 AttributeError: can't set attribute
  • setter 内写 self.images = value 会无限递归,应写 self._images = value
  • @property@classmethod 不能叠在同一 def 上;类级「属性」用描述符或元类

7. 近邻替代

替代 何时用
functools.cached_property 首次访问后缓存结果,适合昂贵计算
普通方法 get_x() 不需要属性语法、无 setter 需求

8. 参考

-------------本文结束感谢您的阅读-------------