我创建了一个用其初始化对象的类 一堆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”,因为它对对象有非常显着的副作用,我对此感到不安。这是一个合理的担忧吗?如果是这样,我该如何解决?
答案 0 :(得分:14)
此设计模式称为Lazy initialization,它具有合法用途。
答案 1 :(得分:4)
虽然吸气剂肯定会产生副作用,但传统上并不是人们认为会产生副作用。由于getter总是返回相同的东西(除非状态中有任何干预变化),它没有用户可见的副作用。这是属性的典型用法,所以没有什么值得关注的。
答案 2 :(得分:0)
几年之后但很好:虽然懒惰的初始化本身很好,但我肯定不会推迟xml解析等,直到有人访问对象title
。计算属性应该像普通属性一样,并且普通属性访问永远不会引发(假设属性当然存在)。
FWIW我在一些项目中遇到了一个非常类似的情况,xml解析错误发生在最意想不到的地方,因为之前的开发人员使用的属性与OP示例中的方式相同,并且必须修复它通过将解析和验证部分放在实例化时间。
因此,只有当知道时,才会使用属性进行延迟初始化永远不会引发。实际上,永远不要将属性用于任何可能引发的事情(至少在获取 - 设置是不同的情况时)。否则,不要使用属性,使getter成为一个明确的方法,并清楚地记录它可能引发这个或那个。
注意:使用属性缓存某些东西不是问题,这本身就没问题。