You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中属性名以__开头时@property setter不生效问题咨询

问题原因

该问题的根本原因是Python的**双下划线名称修饰(Name Mangling)**机制和getattr动态查找的行为差异导致的。

名称修饰规则

  • Python会对类中定义的、满足__开头 + 末尾最多1个下划线格式的标识符自动重命名,重命名规则为_类名__原标识符名,目的是避免类的私有属性被子类或外部意外覆盖。
  • 仅当你在类的代码块中直接书写双下划线开头的属性名时,Python才会自动执行名称修饰;如果是通过字符串形式(比如getattr的第二个参数、__dict__的键)传入的双下划线名称,不会触发修饰逻辑。

两段代码的行为差异分析

第一种写法(正常运行)

存储属性使用_a_,仅开头1个下划线,不满足名称修饰的触发条件,因此getattr查找的_a_和setter中赋值的self._a_是完全相同的属性,读写对应一致,运行正常。

第二种写法(setter不生效)

  1. setter中直接写self.__a = value:属于类代码块内直接使用双下划线标识符,会被自动修饰为self._A__a = value,赋值操作实际是给实例新增了名为_A__a的属性。
  2. getter中使用getattr(self, '__a', 0):'__a'是字符串参数,不会触发名称修饰,getattr会直接查找实例中是否存在名为__a的属性,而实际存储的是_A__a,所以永远找不到,一直返回默认值0,看起来就像setter没有生效。

验证方法

你可以在第二种写法的赋值后打印实例的属性字典验证上述逻辑:

a = A()
a._a = 10
print(a.__dict__)
# 输出:{'_A__a': 10}

可以看到存储的属性名是_A__a而非__a,和分析完全一致。

修复方案

提供两种常用修复方式:

方案1:getattr使用修饰后的属性名

class A:
    @property
    def _a(self):
        # 直接传入修饰后的名称字符串
        return getattr(self, '_A__a', 0)

    @_a.setter
    def _a(self, value):
        self.__a = value

方案2:类内部直接访问属性(推荐)

避免用字符串动态查找,类内部直接访问双下划线属性时会自动触发名称修饰,同时在__init__中初始化属性避免访问报错:

class A:
    def __init__(self):
        self.__a = 0

    @property
    def _a(self):
        return self.__a

    @_a.setter
    def _a(self, value):
        self.__a = value

内容的提问来源于stack exchange,提问作者gioxc88

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 20:36:05