Python使用property装饰器时实例同时存在_<var>与<var>属性问题咨询
Python property装饰器相关问题解答
核心疑问解答
1. 两类属性的本质区别
你看到的两个属性本质完全不同:
_my_var是真实存储的属性:你最初把它定义为类变量,后续给实例赋值后会升级为实例专属属性,存储在实例的__dict__字段中。my_var不是实际存储的属性:它是属于类的property描述符对象,不会出现在实例的__dict__里。你访问x.my_var时,Python会自动调用你定义的getter方法返回_my_var的值,你看到的my_var: None是getter返回的计算值,不是实例实际存储的字段。
你直接修改x._my_var = 10后两个值同步变化,原因就是my_var的getter逻辑本身就是返回_my_var的取值,底层存储值变了,getter返回的结果自然同步更新。
你给出的示例代码存在3处语法错误,修正后可正常运行:
- setter装饰器应该写为
@my_var.setter而非@property.setter- setter方法定义末尾缺少冒号
- 赋值语句应为
self._my_var = value,而非return._my_var = value
修正后的基础代码如下:class A: _my_var = None @property def my_var(self): return self._my_var @my_var.setter def my_var(self, value): # 这里写你的校验逻辑 if value < 0: raise ValueError("值不能为负数") self._my_var = value
2. 强制用户走setter校验的实现方案
Python本身没有强私有属性约束,根据使用场景可以选择两种方案:
方案1:遵循Python社区约定(最常用)
单下划线开头的属性本身就是社区通用的「内部属性,外部不要直接访问」的约定,你只需要在类的文档说明里标注所有修改必须通过my_varsetter即可,绝大多数开发场景下该方案足够用。方案2:使用双下划线名称改写(强限制)
把内部存储属性改成双下划线开头,Python会自动对该属性做名称改写,外部无法直接访问修改,从语法层面强制用户走setter,示例代码如下:class A: def __init__(self): # 双下划线开头,Python会自动改名为 _A__my_var self.__my_var = None @property def my_var(self): return self.__my_var @my_var.setter def my_var(self, value): # 你的校验逻辑 if not isinstance(value, int): raise TypeError("my_var必须为整数") if value < 0: raise ValueError("my_var不能为负数") self.__my_var = value该场景下外部直接执行
x.__my_var = 10不会修改实际的内部属性,只会给实例新增一个无关的__my_var字段,访问x.my_var还是会返回校验后的有效值,完全规避了外部直接修改内部属性的问题。
内容的提问来源于stack exchange,提问作者Malintha
相关产品推荐
相关产品推荐

