假设我需要将传入的数据写入云上的数据集中。何时,何处以及是否需要代码中的数据集,取决于进来的数据。我只想获得一次对数据集的引用。实现这一目标的最佳方法是什么?
-
初始化为开始时的全局变量,并通过全局变量
访问if __name__="__main__": dataset = #get dataset from internet
这似乎是最简单的方法,但是即使不需要变量也可以初始化。
-
首次需要数据集,保存在全局变量中,并使用
get_dataset()
方法访问dataset = None def get_dataset(): global dataset if dataset is none dataset = #get dataset from internet return dataset
-
首次需要数据集,并将其保存为函数属性,并使用
get_dataset()
方法访问def get_dataset(): if not hasattr(get_dataset, 'dataset'): get_dataset.dataset = #get dataset from internet return get_dataset.dataset
-
任何其他方式
做您想做的事情的典型方法是包装服务,要求数据进入类:
class MyService():
dataset = None
def get_data(self):
if self.dataset = None:
self.dataset = get_my_data()
return self.dataset
然后,您将其实例化一次在您的主体中,并在需要的任何地方使用。
if __name__="__main__":
data_service = MyService()
data = data_service.get_data()
# or pass the service to whoever needs it
my_function_that_uses_data(data_service)
dataset
变量是内部的,但可以通过可发现的函数访问。您也可以在类的实例上使用property
。
另外,使用对象和类使在大型项目中更加清楚,因为该功能应该从类别和方法中自称。
请注意,您也可以轻松地使其成为通用服务,并将其传递给初始化中的数据(如URL?),因此可以用不同的端点重新使用。
要避免的一个警告是在您的子模型中多次实例化相同的类,而不是主编码。如果这样做,则将为每个实例获取并存储数据。另一方面,您可以将类的实例传递给子模块,并且只能在需要时获取数据(即,如果您的子模块不需要,可能永远不会获取它),而使用所有选项,则数据集需要先获取其他地方。
注意您提出的选项:
- 在
if __name__ == '__main__'
部分中初始化:
如果您将模块称为模块,则不会在全球初始初始化(仅在调用shell调用模块时会初始化)。
即使您不需要Main。
- 在函数中设置全局。
通常不建议使用global
,就像任何编程语言一样。从范围中修改变量是遇到奇数行为的食谱。如果您依靠仅在特定工作流程中设置的全局,它也倾向于使代码更难测试。
- 函数上的属性
这是一种眼神:它肯定会起作用,并且功能与我提出的Class
模式非常相似,但是您必须接受功能上的属性。类的优点是,您可以以多种方式将其初始化,可以将其子类等起来,却不能在需要之前获取数据。使用直函数是"更简单",但更有限。
您也可以使用functools
模块中的lru_cache
装饰器来实现仅运行一次昂贵操作的目标。
只要参数相同,请一次又一次调用函数。
https://docs.python.org/3/library/functools.html#functools.lru_cache
@lru_cache
def fun(input1, input2):
... # expensive operation
return result
类似于MRE的答案,最好用包装器将数据封装。
但是,我建议您使用python闭合python闭合而不是类。
应该使用类来封装与数据密切相关的数据和相关功能。一个类应该是您将实例化对象的东西,并且对象将保留个性。您可以在此处阅读有关此信息的更多信息
您可以使用以下方式使用封闭
def get_dataset_wrapper():
dataset = None
def get_dataset():
nonlocal dataset
if dataset is none
dataset = #get dataset from internet
return dataset
return get_dataset
您可以以以下方式使用它
dataset = get_dataset_wrapper()()
如果()()语法会困扰您,则可以这样做:
def wrapper():
return get_dataset_wrapper()()