14

我创建了一个类,它的对象是用一堆 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”函数,因为它对对象有非常显着的副作用,这让我有点不安。这是一个合理的担忧吗?如果是这样,我应该如何解决它?

4

3 回答 3

15

这种设计模式称为延迟初始化,它具有合法用途。

于 2011-01-19T19:17:53.220 回答
5

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

于 2011-01-19T19:35:00.887 回答
1

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

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

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

注意:使用属性来缓存某些东西在这里不是问题,这本身就很好。

于 2017-11-24T09:28:52.240 回答