【问题标题】:Python: Using getter or "private" attribute inside setter?Python:在 setter 中使用 getter 或“私有”属性?
【发布时间】:2012-11-18 19:14:06
【问题描述】:

假设我有一个类NamedObject,它有一个属性name。现在,如果我必须使用 setter,我首先必须像这样定义一个 getter(我猜?):

class NamedObject:
    def __init__(self, name):
        self.name = name

    @property
    def name(self):
        return self._name

现在我想知道,在 setter 内部,我应该使用 self._name 还是 self.name,getter 还是实际属性?设置名称时,I ofc。需要使用_name,但是当我进入二传手时呢?例如:

@name.setter
def name(self, value):
    if self._name != str(value): # Or should I do 'if self.name != value' ?
        self.doStuff(self._name) # Or doStuff(self.name) ?
        self.doMoreStuff()
        self._name = str(value)

使用哪一个真的很重要吗?为什么要使用一个而不是另一个?

【问题讨论】:

  • 在 Python 中,您通常根本不使用 getter 和 setter。
  • 为什么不呢?那它们为什么存在呢? O.o 我要求的每个人都告诉我使用它们,并且每个人都告诉我不要。
  • @Mahi 当你真正有 理由 使用它们时使用它们 - 例如。您想做的不仅仅是直接分配和读取属性的值(例如验证)。
  • 您通常首先只使用实例属性,然后当您认为必须添加一些操作/控件来获取/设置时,您将其更改为属性,这样您就可以向后改进代码兼容的方式。添加不做任何事情的随机 getter/setter 只是编写更多代码,而没有提供任何类型的信息隐藏或功能。
  • @Amber 是的,对不起,这是我在那里提出的一个坏例子(主要帖子),但在我的实际代码中,我在 setter 上有 15 行代码,而在 getter 上只有一个.我应该使用 getter 和 setter 吗?

标签: python python-3.x getter-setter private-members


【解决方案1】:

当您的设置器是内部接口的一部分时,没有正常理由使用外部接口。我想你也许可以构建一个你可能想要的场景,但默认情况下,只使用内部变量。

【讨论】:

    【解决方案2】:

    如果您的 getter 具有重要的逻辑(如延迟初始化),那么您应该始终通过 getter 访问。

    class Something(object):
        UNINITIALIZED = object()
        LAZY_ATTRS = ('x','y','z')
        def __init__(self):
            for attr in self.LAZY_ATTRS:
                setattr(self, '_'+attr, self.UNINITIALIZED)
        def _get_x(self):
            if self._x is self.UNINITIALIZED:
                self._x = self.doExpensiveInitStuff('x')
            return self._x
    

    但如果你的 getter 所做的只是return self._x,那么直接访问内部变量即可。

    【讨论】:

      【解决方案3】:

      使用 getter 而不是仅仅访问内部变量会为您的设置逻辑添加另一个函数调用,并且在 Python 中,函数调用是昂贵的。如果你正在写这个:

      def _get_x(self):
          return self._x
      
      def _set_x(self, value):
          self._x = value
      x = property(fget=_get_x, fset=_set_x)
      

      那么您患有“Too Much Java”综合症。 Java 开发人员必须编写这类东西,因为如果以后有必要为 x 的设置或获取添加行为,则必须重新编译所有在类之外对 x 的访问。但是在 Python 中,最好保持简单,只需将 x 定义为实例变量,并仅在需要添加某种设置或获取行为时才转换为属性。见YAGNIYAGNI

      【讨论】:

      • 阅读我对主帖的第二条评论。我来自 C++ 方面,而不是 Java,但我想它们几乎相同。实际上,我的 setter 中有 15 行代码,为了这个问题,我只是写了一个简单的例子。所以这又没有回答我的实际问题,但我想我应该责怪自己给出了一个糟糕的示例代码:P
      • 您从简单示例中得到的是在 Python 中使用属性的传统智慧:“在需要之前不要这样做。”如果您的 getter 所做的只是 return self._name,那么只需在您的 setter 中访问 self._name,并避免不必要的函数调用。如果您稍后还需要向 getter 添加行为,并且此行为在 setter 中很重要,那么您可能已经足够接近 setter 代码来追踪对self._name 的违规直接引用。
      【解决方案4】:

      保罗已经回答得很好。

      为了完整起见,我想补充一点,始终如一地使用 getter/setter 可以更轻松地覆盖类。这里有几个含义。

      如果您设想某个特定类很可能会被您或其他人覆盖/扩展,那么尽早使用 getter/setter 可能会在以后花费更少的时间进行重构方面有所帮助。不过,我同意保持简单的观点:由于运行时成本和阅读/编码工作量,请谨慎使用以下内容。

      如果在 getter 中也进行了验证,那么要么直接在 setter 中使用实例属性,要么提供两个不同的 getter name()_name()(或 name_already_checked()),以便两者都可以被覆盖并使用在 setter 中没有验证的简单 getter。这是为了允许扩展快速、无验证类型的 getter 以及为客户提供的通常类型的 getter。

      这确实违反了Paul pointed to 的 YAGNI 原则。但是,如果您确实为更广泛的受众发布代码,“过度工程”通常是可取的。图书馆受益于增加的灵活性和远见。

      【讨论】:

        猜你喜欢
        • 2017-06-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-30
        • 2018-07-16
        • 1970-01-01
        相关资源
        最近更新 更多