我有一组非常大且计算成本昂贵的数组,并且在任何给定的运行中我的代码都不一定需要这些数组.我想让他们的声明可选,但理想情况下无需重写我的整个代码.
现在的示例:
x = function_that_generates_huge_array_slowly(0)
y = function_that_generates_huge_array_slowly(1)
Run Code Online (Sandbox Code Playgroud)
我想做的例子:
x = lambda: function_that_generates_huge_array_slowly(0)
y = lambda: function_that_generates_huge_array_slowly(1)
z = x * 5 # this doesn't work because lambda is a function
# is there something that would make this line behave like
# z = x() * 5?
g = x * 6
Run Code Online (Sandbox Code Playgroud)
虽然如上所述使用lambda实现了所需的效果之一 - 数组的计算延迟到需要时 - 如果多次使用变量"x",则必须每次计算.我想只计算一次.
编辑:经过一些额外的搜索,看起来有可能做我想要的(大约)类中的"懒惰"属性(例如http://code.activestate.com/recipes/131495-lazy-attributes/) .我不认为没有单独的课程可以做任何类似的事情吗?
编辑2:我正在尝试实现一些解决方案,但我遇到了一个问题,因为我不明白它们之间的区别:
class sample(object):
def __init__(self):
class one(object):
def __get__(self, obj, type=None):
print "computing ..."
obj.one = 1
return 1
self.one = one()
Run Code Online (Sandbox Code Playgroud)
和
class sample(object):
class one(object):
def __get__(self, obj, type=None):
print "computing ... "
obj.one = 1
return 1
one = one()
Run Code Online (Sandbox Code Playgroud)
我认为这些的一些变化是我正在寻找的,因为昂贵的变量旨在成为一个类的一部分.
问题的前半部分(重用值)很容易解决:
class LazyWrapper(object):
def __init__(self, func):
self.func = func
self.value = None
def __call__(self):
if self.value is None:
self.value = self.func()
return self.value
lazy_wrapper = LazyWrapper(lambda: function_that_generates_huge_array_slowly(0))
Run Code Online (Sandbox Code Playgroud)
但你还是把它当作lazy_wrapper()
没有lasy_wrapper
.
如果您要多次访问某些变量,则使用起来可能会更快:
class LazyWrapper(object):
def __init__(self, func):
self.func = func
def __call__(self):
try:
return self.value
except AttributeError:
self.value = self.func()
return self.value
Run Code Online (Sandbox Code Playgroud)
这会使第一次调用变慢,后续使用更快.
编辑:我发现你找到了一个类似的解决方案,要求你在类上使用属性.无论哪种方式都需要你重写每个懒惰的变量访问,所以只需选择你喜欢的.
编辑2:你也可以这样做:
class YourClass(object)
def __init__(self, func):
self.func = func
@property
def x(self):
try:
return self.value
except AttributeError:
self.value = self.func()
return self.value
Run Code Online (Sandbox Code Playgroud)
如果要x
作为实例属性进行访问.不需要额外的课程.如果您不想更改类签名(通过使其需要func
,您可以将函数调用硬编码到属性中).
编写一个类更强大,但为了简单而优化(我认为你要求),我提出了以下解决方案:
cache = {}
def expensive_calc(factor):
print 'calculating...'
return [1, 2, 3] * factor
def lookup(name):
return ( cache[name] if name in cache
else cache.setdefault(name, expensive_calc(2)) )
print 'run one'
print lookup('x') * 2
print 'run two'
print lookup('x') * 2
Run Code Online (Sandbox Code Playgroud)
Python 3.2和更高版本在functools模块中实现了LRU算法,以处理简单的缓存/存储情况:
import functools
@functools.lru_cache(maxsize=128) #cache at most 128 items
def f(x):
print("I'm being called with %r" % x)
return x + 1
z = f(9) + f(9)**2
Run Code Online (Sandbox Code Playgroud)