如何以Pythonic方式使用@cached_property为Python类设置永久属性?
问题描述
想要为Python类的实例设置一个在其生命周期内可被其他方法调用的永久属性。现有Test类代码如下:
class Test: @cached_property def datafile_num_rows(self) -> int: return self def set_num_rows(self): # insert some calculations calcs = 2 self.datafile_num_rows = calcs
调用示例:
In [118]: x = Test() In [119]: x.set_num_rows() In [120]: x.datafile_num_rows Out[120]: 2
该实现能得到正确结果,但return self的写法逻辑怪异,不符合cached_property的设计初衷,请问最规范、最符合Pythonic风格的实现方式是什么?
符合Pythonic的实现方案
1. 直接初始化实例属性(最简洁)
这是日常开发中最常用的写法,在__init__中明确定义属性,后续通过方法修改即可:
class Test: def __init__(self): # 初始化属性,可设为None或业务默认值 self.datafile_num_rows = None def set_num_rows(self): # 执行具体计算逻辑 calcs = 2 self.datafile_num_rows = calcs
调用逻辑和原代码完全一致,属性的存在和修改逻辑清晰,无需依赖额外装饰器,直观易懂。
2. 使用@property搭配setter(适合需要属性校验的场景)
如果需要对属性的赋值做合法性校验,或者希望属性访问有更严格的控制,可以用@property定义读接口,配套setter方法处理赋值:
class Test: def __init__(self): # 用下划线开头表示内部属性,约定外部直接通过datafile_num_rows访问 self._datafile_num_rows = None @property def datafile_num_rows(self) -> int: if self._datafile_num_rows is None: raise ValueError("属性未初始化,请先调用set_num_rows") return self._datafile_num_rows @datafile_num_rows.setter def datafile_num_rows(self, value: int): # 可添加校验逻辑,比如确保是正整数 if not isinstance(value, int) or value <= 0: raise ValueError("行数必须是正整数") self._datafile_num_rows = value def set_num_rows(self): calcs = 2 self.datafile_num_rows = calcs
这种方式既保留了属性的简洁访问语法,又能对赋值过程做控制,适合业务逻辑严谨的场景。
3. 修正cached_property的用法(仅适合延迟计算场景)
如果原本想用cached_property实现延迟加载(即只有在第一次访问属性时才计算),原代码的写法完全偏离了它的设计,正确的用法应该是让装饰的方法负责计算逻辑:
from functools import cached_property class Test: def __init__(self): self._calculated = False self._rows = None @cached_property def datafile_num_rows(self) -> int: if not self._calculated: # 这里可以直接写计算逻辑,或者调用set_num_rows self.set_num_rows() return self._rows def set_num_rows(self): calcs = 2 self._rows = calcs self._calculated = True
不过这种方式仅当属性计算成本高、且可能不会被频繁访问时才值得使用,否则不如前两种直接。
内容的提问来源于stack exchange,提问作者metersk
相关产品推荐
相关产品推荐

