我有一个如下所示的自定义类。正如命名所暗示的那样,这个想法是我想在解析器类型工具中评估令牌流。一旦解析出一堆构造并将其放入数据结构中,某些令牌序列将评估为int,但是当数据结构尚未可用时,函数只返回None。这种单一的复杂数据结构构建了#39;几乎无处不在程序中传播。
class Toks(list):
def __init__(self, seq, constructs=Constructs()):
list.__init__(self, seq)
self.constructs = constructs
@property
def as_value(self):
val = tokens_as_value(self, self.constructs)
return val if val is not None else self
在代码中的点,我想将这个可计算的值分配给一个名称,例如:
mything.val = Toks(tokens[start:end], constructs).as_value
好吧,这给了mything.val
一个实际的int值或一个有趣的东西,它允许我们稍后计算一个值。但是这需要稍后的传递来实际执行计算,类似于:
if not isinstance(mything.val, int):
mything.val = mything.val.as_value
碰巧,我可以在我的程序中执行此操作。然而,我真正想要发生的是完全避免第二次传递,只是有权访问属性执行计算并给出计算值,如果它在那时可计算(并且可能评估为如果不可能计算,则为某些sentinal。
有什么想法吗?
澄清:根据具体情况,我得到"价值"不同的;实际代码更像是:
if tok.type == 'NUMBER':
mything.val = tok.value # A simple integer value
else:
mything.val = Toks(tokens[start:end], constructs).as_value
还有其他情况,有时我知道我早知道实际价值,有时候我不确定我以后是否只会知道它。
我意识到我可以推迟呼叫(比@dana建议的更紧凑):
return val if val is not None else lambda: self.as_value
但是,这使得以后的访问权限在mything.val
和mything.val()
之间不一致,因此我仍然需要使用if
来保护它以查看要使用的样式。在类型检查后我是否需要回退到mything.val.as_value
或mything.val()
会带来同样的不便。
答案 0 :(得分:0)
您可以轻松地执行以下操作:
class NaiveLazy(object):
def __init__(self, ctor):
self.ctor = ctor
self._value = None
@property
def value(self):
if self._value is None:
self._value = ctor()
return self._value
mything = NaiveLazy(lambda: time.sleep(5) and 10)
然后总是使用mything.value(示例评估示例):
print mything.value # will wait 5 seconds and print 10
print mything.value # will print 10
我已经看到一些实用程序库在ctor返回None
的情况下为undefined创建一个特殊对象。如果你最终希望将代码扩展到整数以外,你应该考虑一下:
class Undefined(object): pass
UNDEFINED = Undefined()
#...
self._value = UNDEFINED
#...
if self._value is UNDEFINED: self._value = ctor()
具体为您的例子:
def toks_ctor(seq, constructs=Constructs()):
return lambda l=list(seq): tokens_as_value(l, constructs) or UNDEFINED
mything = NaiveLazy(toks_ctor(tokens[start:end], constructs))
答案 1 :(得分:0)
如果您使用的是Python3.2 +,请考虑使用Future对象。此工具允许您在后台运行任意数量的计算。您可以等待单个未来完成,并使用其值。或者,您可以在完成后逐个“流式传输”结果。
答案 2 :(得分:0)
您可以从as_value
返回一个可调用对象,这样您就可以自动检查实际返回值。一个缺点是您需要使用mything.val()
而不是mything.val
:
def tokens_as_value(toks, constructs):
if constructs.constructed:
return "some value"
else:
return None
class Constructs(object):
def __init__(self):
self.constructed = False
class Toks(list):
def __init__(self, seq, constructs=Constructs()):
list.__init__(self, seq)
self.constructs = constructs
@property
def as_value(self):
return FutureVal(tokens_as_value, self, self.constructs)
class FutureVal(object):
def __init__(self, func, *args, **kwargs):
self.func = func
self._val = None
self.args = args
self.kwargs = kwargs
def __call__(self):
if self._val is None:
self._val = self.func(*self.args, **self.kwargs)
return self._val
仅出于示例的目的,Constructs
只包含一个布尔值,指示是否应从tokens_as_value
返回实际值。
用法:
>>> t = test.Toks([])
>>> z = t.as_value
>>> z
<test.FutureVal object at 0x7f7292c96150>
>>> print(z())
None
>>> t.constructs.constructed = True
>>> print(z())
our value