【问题标题】:Getter with side effect有副作用的吸气剂
【发布时间】:2011-06-11 23:52:33
【问题描述】:

我创建了一个类,其对象被初始化为 一堆 XML 代码。该类能够从 XML 中提取各种参数并将它们缓存在对象状态变量中。这些参数的潜在数量很大,用户很可能不需要其中的大部分。这就是我决定执行“惰性”初始化的原因。

在下面的测试用例中,这样的参数是title。当用户第一次尝试访问它时,getter 函数会解析 XML,正确初始化状态变量并返回其值:

class MyClass(object):     
    def __init__(self, xml=None):
        self.xml  = xml
        self.title = None

    def get_title(self):
        if self.__title is None:
            self.__title = self.__title_from_xml()
        return self.__title

    def set_title(self, value):
        self.__title = value

    title = property(get_title, set_title, None, "Citation title")

    def __title_from_xml(self):
        #parse the XML and return the title
        return title         

这看起来不错,对我来说很好用。但是,getter 函数实际上是一个“setter”函数,因为它对对象有非常显着的副作用,这让我有点不安。这是一个合理的担忧吗?如果是这样,我应该如何解决?

【问题讨论】:

  • 无论问题的实际答案是什么,您都不应该使用前导双下划线。他们开始名称修改,即很多潜在的痛苦和零收益。只需使用一个前导下划线。
  • 我不明白为什么这是个问题。
  • 小重构建议:不要在构造函数中初始化self._title,将getter中的条件替换为not hasattr(self, "_title")
  • @delnan:这是 Eclipse 的 PyDev 默认创建属性的方式。
  • @Sven Marnach: not hasattr(self, '_title') 对于延迟初始化来说并不常见,并且也会比正常的属性查找和针对 None 的测试慢。

标签: python design-patterns for-loop getter-setter side-effects


【解决方案1】:

这种设计模式称为Lazy initialization,它有合法用途。

【讨论】:

  • cf 我对已接受答案的评论 - 延迟初始化很好,但这并不意味着应该允许属性访问引发任何事情。如果您的类使用延迟初始化,请确保这永远不会暗示任何异常,或者不要诱使用户认为他正在执行简单的安全属性访问并使您的 getter 成为显式方法,记录它可能引发的事实或那个例外。
【解决方案2】:

虽然 getter 肯定会产生副作用,但传统上这并不是人们认为不好的副作用。由于 getter 总是返回相同的东西(除非状态发生任何干预变化),它没有用户可见的副作用。这是属性的典型用途,因此无需担心。

【讨论】:

  • 我不同意:在这种情况下,解析 xml 会引发异常,并且没有人期望属性访问会引发一些 xml 解析异常。我在一个项目中遇到了一个非常相似的案例,我接手并重写了这部分代码,以便在实例化时进行解析,因此如果 xml 以任何方式损坏,在后期不会发生异常。 get 属性不应该引发任何异常。您是否期望一个普通的属性访问来引发任何事情(当然假设该属性存在)?计算属性应该和普通属性一样安全。
【解决方案3】:

很多年后,但很好:虽然延迟初始化本身很好,但我绝对不会推迟 xml 解析等,直到有人访问对象的 title。计算属性应该表现得像普通属性,并且普通属性访问将从不引发(当然假设属性存在)。

FWIW 在我接手的某个项目中,我遇到了一个非常相似的案例,xml 解析错误发生在最意想不到的地方,因为之前的开发人员使用属性的方式与 OP 示例中的方式完全相同,因此必须修复它通过将解析和验证部分放在实例化时。

因此,只有当您知道第一次访问永远不会引发时,才使用延迟初始化属性。实际上,永远不要将属性用于可能引发的任何事情(至少在获取时 - 设置是不同的情况)。否则,不要使用属性,使 getter 成为显式方法并清楚地记录它可能会引发这个或那个。

注意:这里使用属性缓存不是问题,这本身就很好。

【讨论】:

    猜你喜欢
    • 2019-11-26
    • 2018-11-16
    • 2023-02-02
    • 1970-01-01
    • 2018-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多