首页 > 解决方案 > 使用属性装饰器后,python 对象有两个非常相似的属性(foo.bar 和 foo._bar)。那样行吗?

问题描述

所以我正在重构我的代码,使其更加 Pythonic——特别是我了解到,使用显式 getter 和 setter 应该替换为 @property。我的情况是我有一个Example具有初始化bar属性的类(初始化帮助我知道用户设置了bar):

class Example:
  def __init__(self):
    self.bar = 'initializedValue'

  @property
  def bar(self):
    return self._bar

  @bar.setter
  def bar(self, b):
    self._bar = b

  def doIfBarWasSet():
    if self.bar != 'initializedValue':
      pass
    else:
      pass

运行foo = Example()我的调试器后显示 foo 有两个属性:_barbar,都设置为'initializedValue'. 此外,当我运行foo.bar = 'changedValue'or时foo._bar = 'changedValue',它们都更改为'changedValue'. 为什么有两个属性?这不是多余的吗?我想我明白为什么会有_bar属性 - 我将它添加到 中@bar.setter,但为什么会有bar字符串属性?不应该bar是一种导致的方法bar @property吗?

标签: pythonpython-3.xpropertiesdecorator

解决方案


没关系。请记住,这bar不是实例属性,而是属性。由于它具有 type property,因此它实现了描述符协议,因此当从实例访问时它的行为是不同的。如果e是 的实例Examplee.bar则不给您property分配给的实例Example.bar;它为您提供了结果Example.bar.__get__(e, Example)(在这种情况下,恰好是Example.bar.fget(e)fget由 装饰的原始函数在哪里@property)。

简而言之,每个实例都有自己的_bar属性,但对该属性的访问是由类属性介导的Example.bar


bar如果您编写这个最小(并且足够,因为在这种情况下 getter 和 setter 都不需要def语句)定义,则更容易看出这是一个类属性。

class Example:
    def __init__(self):
        self.bar = "initalizedValue"

    bar = property(lambda self: self._bar, lambda self, b: setattr(self, '_bar', b))

或更一般地说

def bar_getter(self):
    return self._bar


def bar_setter(self, b):
    self._bar = b


class Example:
    def __init__(self):
        self.bar = "initalizedValue"

    bar = property(bar_getter, bar_setter)

推荐阅读