【问题标题】:Property setter not working when attribute starts with "__"?当属性以“__”开头时,属性设置器不起作用?
【发布时间】:2021-12-30 19:37:26
【问题描述】:

我正在使用 Python 3.8.6,这工作正常

class A:
    @property
    def _a(self):
        return getattr(self, '_a_', 0)

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


a = A()
print(a._a)  # prints 0
a._a = 10
print(a._a)  # prints 10 as expected

这行不通

class A:
    @property
    def _a(self):
        return getattr(self, '__a', 0)

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

a = A()
print(a._a)  # prints 0
a._a = 10
print(a._a)  # prints 0 again

这真是令人兴奋!第一个和第二个例子的唯一区别是私有属性是__a而不是_a_

知道为什么吗?我无法弄清楚

【问题讨论】:

  • 可能与前导双下划线表示的私有属性/方法有关,请参阅docs.python.org/3/tutorial/…
  • 这确实解释了原因。如果你写一个答案,我会接受它作为一个解决方案。 “__spam 形式的任何标识符(至少两个前导下划线,最多一个尾随下划线)在文本上替换为 _classname__spam,其中 classname 是当前类名,前导下划线被剥离。这种修改是在不考虑句法的情况下完成的标识符的位置,只要它出现在类的定义中。”

标签: python properties


【解决方案1】:

这是由于private name mangling,但它不适用于字符串文字的内容,例如您传递给getattr() 的内容。

幸运的是,修复很简单:

class A:
    @property
    def _a(self):
        return getattr(self, '_A__a', 0)

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

a = A()
print(a._a)  # prints 0
a._a = 10
print(a._a)  # prints 10 now

【讨论】:

  • 我认为使用classname 的变体会破坏子类,因为setter 是写在基类中的,所以属性名称仍然会被修改为_A__a
  • @kaya3:“打破”它有什么意义?它使用了一个子类的名称。
  • 好吧,如果class B(A): pass 那么b = B(); b._a = 23; print(b._a) 将打印0,因为setter 写入_A__a 但getter 尝试访问_B__a
  • @kaya3:你是对的,所以我删除了我的答案的那部分。
猜你喜欢
  • 1970-01-01
  • 2016-12-07
  • 1970-01-01
  • 2013-01-02
  • 2021-09-10
  • 1970-01-01
  • 2012-10-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多