我有一个实用程序模块,用于向其他脚本提供数据。我无法理解利用它的最佳方式,同时最大限度地减少函数调用的数量(为了论证,这些都是缓慢的)。
它看起来像这样:
helper.py
dataset1 = slow_process1()
dataset2 = slow_process2()
def get_specific_data1():
data = #do stuff with dataset1
return data
def get_specific_data2():
data = #do stuff with dataset1
return data
def get_specific_data3():
data = #do stuff with dataset2
return data
现在,我需要在脚本中运行get_specific_data1
。在上面的设置中,我导入了模块,这意味着我在导入时不必要地调用slow_process2
。
如果我嵌套dataset1
和dataset2
的作业,但需要在同一个脚本中调用get_specific_data1
和get_specific_data2
,我会运行slow_process1
两次,这也是不必要的。
如果我使用Helper
函数的方法创建get_specific_data
类,如果需要,它运行slow_process1
或slow_process2
,存储数据,然后可以根据需要访问当调用方法时,我可以解决这个问题。这是合适的吗?
类似的东西:
class Helper:
def __init__(self):
self.dataset1 = None
self.dataset2 = None
def run_dataset1():
self.dataset1 = slow_process1()
def run_dataset2():
self.dataset2 = slow_process2()
def get_specific_data1():
if dataset1 is None:
self.rundataset1()
data = #do stuff with dataset1
return data
etc
道歉,如果这是一个愚蠢的问题,但我对OOP的经验有限,并且不想在前面犯错误。
由于
答案 0 :(得分:1)
您可以使用延迟加载技术解决此问题:
dataset1 = None
dataset2 = None
def ensureDataset1():
global dataset1
if dataset1 is None:
dataset1 = slow_process1()
def ensureDataset2():
global dataset2
if dataset2 is None:
dataset2 = slow_process2()
def get_specific_data1():
ensureDataset1()
data = #do stuff with dataset1
return data
etc
这里的副作用是,如果你永远不会去检查dataset1
或dataset2
,他们永远不会加载。
答案 1 :(得分:1)
这就是我使用properties类的意思,只是在这种情况下,我使用了名为Added support for more in depth searching
的自定义版本。它被认为是"懒惰"因为只有当它被访问时才会被计算,就像常规的lazyproperty
一样,但与它们不同的是,计算出的值有效地被高速缓存,从而将其变为实例属性 - 因此它赢得了每次都要重新计算。
警告:这样做假设无论何时计算该值都是相同的,并且在第一次访问后对其进行的任何更改将对同一实例的其他方法可见。使用它的类 - 即他们不会看到新重新计算的值。
完成此操作后,类中的方法可以引用property
或self.dataset1
,就像它们是常规实例属性一样,然后,如果它是第一次,则数据将计算与之关联的值,否则将仅返回先前创建的值的值。您可以在生成的输出中看到这种情况(如下所示)。
self.dataset2
输出:
# From the book "Python Cookbook" 3rd Edition.
class lazyproperty:
def __init__(self, func):
self.func = func
def __get__(self, instance, cls):
if instance is None:
return self
else:
value = self.func(instance)
setattr(instance, self.func.__name__, value)
return value
def slow_process1():
print('slow_process1() running')
return 13
def slow_process2():
print('slow_process2() running')
return 21
class Helper:
def __init__(self):
""" Does nothing - so not really needed. """
pass
@lazyproperty
def dataset1(self):
return slow_process1()
@lazyproperty
def dataset2(self):
return slow_process2()
def process_data1(self):
print('self.dataset1:', self.dataset1) # doing stuff with dataset1
return self.dataset1 * 2
def process_data2(self):
print('self.dataset2:', self.dataset2) # doing stuff with dataset2
return self.dataset2 * 2
def process_data3(self):
print('self.dataset2:', self.dataset2) # also does stuff with dataset2
return self.dataset2 * 3
if __name__ == '__main__':
helper = Helper()
print(helper.process_data1()) # Will cause slow_process1() to be called
print(helper.process_data2()) # Will cause slow_process2() to be called
print(helper.process_data3()) # Won't call slow_process2() again