在模块中初始化变量的最佳方法?

Rob*_*bbe 11 python initialization global-variables function-attributes

假设我需要将传入数据写入云上的数据集。我何时、何地以及是否需要在代码中使用数据集,取决于传入的数据。我只想获取对数据集的引用一次。实现这一目标的最佳方法是什么?

  1. 启动时初始化为全局变量并通过全局变量访问

    if __name__="__main__":
        dataset = #get dataset from internet
    
    Run Code Online (Sandbox Code Playgroud)

这看起来是最简单的方法,但即使从不需要它也会初始化该变量。

  1. 第一次需要数据集时获取引用,保存在全局变量中,并通过get_dataset()方法访问

    dataset = None
    
    def get_dataset():
        global dataset
        if dataset is none
            dataset = #get dataset from internet
        return dataset
    
    Run Code Online (Sandbox Code Playgroud)
  2. 第一次需要数据集时获取参考,保存为函数属性,并通过get_dataset()方法访问

    def get_dataset():
        if not hasattr(get_dataset, 'dataset'):
            get_dataset.dataset = #get dataset from internet
        return get_dataset.dataset
    
    Run Code Online (Sandbox Code Playgroud)
  3. 任何其他方式

MrE*_*MrE 8

执行您想要的操作的典型方法是将调用数据的服务包装到一个类中:

class MyService():
  dataset = None

  def get_data(self):
    if self.dataset = None:
      self.dataset = get_my_data()
    return self.dataset
    
Run Code Online (Sandbox Code Playgroud)

然后,您在主程序中实例化一次并在需要的地方使用它。

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)
Run Code Online (Sandbox Code Playgroud)

dataset变量是内部变量,但可以通过可发现的函数访问。property您还可以在类的实例上使用 a 。

此外,使用对象和类使得在大型项目中变得更加清晰,因为功能应该从类名和方法中不言自明。

请注意,您也可以轻松地将其设为通用服务,通过在初始化中获取数据的方式传递给它(例如 url?),这样它就可以在不同的端点上重复使用。

要避免的一个警告是在子模块中多次实例化同一个类,而不是在主模块中。如果这样做,将为每个实例获取并存储数据。另一方面,您可以将类的实例传递给子模块,并且仅在需要时获取数据(即,如果您的子模块从不需要它,则可能永远不会获取数据),而使用所有选项时,数据集需要先获取才能传递到其他地方。

请注意您建议的选项:

  1. 在该部分初始化if __name__ == '__main__'

如果您要将模块作为模块调用,则不会对其进行全局初始化(仅当从 shell 调用模块时才会对其进行初始化)。

您需要获取数据以将其传递到其他地方,即使您在 main 中不需要它。

  1. 在函数内设置全局。

通常不鼓励使用global,就像在任何编程语言中一样。修改超出范围的变量是遇到奇怪行为的秘诀。如果您依赖于仅在特定工作流程中设置的全局变量,它也往往会使代码更难测试。

  1. 函数的属性

这个有点让人眼花缭乱:它肯定可以工作,而且功能与Class我提出的模式非常相似,但你必须承认函数上的属性不是很Pythonic。该类的优点是您可以通过多种方式初始化它,可以对其进行子类化等,但在需要时才获取数据。使用直接函数更“简单”,但也有更多限制。