关于命名空间:如何初始化一次python对象并在其他模块之间共享?

How to initialize a python object once and share across other modules?

对于我的生活,我发现我的python转换非常令人沮丧。我正在尝试做的一件事是从配置字典初始化类的单个实例,然后在其他模块中访问该类。

我所面临的问题/我所采取的方法都没有解决,我希望有人能用正确的"Python"方法。

首先,我的应用程序可以作为扭曲插件的一部分进行初始化,或者作为独立脚本进行初始化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import resource
class App(object):
  _config = None
  _someotherobject = None
  def __init__(self, config):
    self._config = config
    ....

def main():
  global myapp
  myapp = App({}) # Could use help here, how to pass config to it

myapp = None #Global doesnt work as I expect, it doesnt modify this instance, stays as None
if __name__ == '__main__':
  main()


#-----------resource.py
class Foo(object):
  def foo(self):
    app.myapp.somefunction() #NoneType object has no attribute

在启动其他模块中的代码之前,我已经验证了是否创建了应用程序对象。我只是不明白模块中的"全局"实例为什么没有实际执行我所期望的操作,也不明白如何引用另一个模块中的实例。

-----编辑------为了澄清几个问题,脚本是用python app.py调用的。py引用了一个名为resources.py的模块,它是一组类定义。在一些类中,当执行时,它们引用app.myapp的"singleton"实例。


只有当从另一个模块导入时,才会以独立脚本的形式调用您的main

1
2
if __name__ == '__main__':
  main()

使模块可以从命令行运行的技巧。

证明它

1
2
import app
app.main()

然后运行你的代码。

一旦您初始化了它,app就变成了一个单例,任何其他导入它的模块都将得到初始化的版本。

我有一个类似的问题,我不想访问app,但希望模块能够说app = MyApp(),并且仍然共享相同的数据(我忘记了为什么需要它,但它可能与希望它在第一次使用时初始化有关)。

我最后用的是博格而不是单胎。


要清除一点,下面是一个示例:

1
2
3
4
5
6
7
8
9
10
11
class App:
    _config = None
    _someotherobject = None

def __init__(self, config):
    self._config = config

def main():
  myapp = App(config) # pass a config object to App

if  __name__ =='__main__':main()

在另一个应用程序中,您必须执行以下操作:

1
2
3
from first_app import App

myapp = App(config)


你最大的问题就是索塔普提到的那个。如果您没有将app.py作为顶级脚本运行,那么就没有任何代码调用app.main(),因此也没有初始化全局脚本。

除此之外,"如何从另一个模块引用实例"非常简单,如果您知道一件简单的事情:

在python中,全局是有名称空间的。

更具体地说,在您的其他模块中,只有import app,然后以app.myapp的形式访问全局。

正如sotapme所解释的那样,使用__name__ == '__main__'技巧意味着你可以随心所欲地多次使用import app,而不必每次都运行main()功能。

尤其是在运行此命令时:

1
python app.py

python解释器将加载app.py,其__name__设置为'__main__',因此if语句将触发,这将导致(模块级)全局变量myapp设置为App({})

现在,当resource.py执行import app时,其__name__将被设置为app,因此if语句不会触发,因此您将构造一个新的app并替换全局。从resource.py中的代码可以使用app.myapp,您将访问与app.py中的代码所看到的myapp相同的对象。

您还请求帮助将config传递给app构造函数。我不知道你的问题在这里。您正在传递一个空的dict作为配置。如果你要通过一个不同的dict,就使用它。而不是这个:

1
myapp = App({}) # Could use help here, how to pass config to it

这样做:

1
myapp = App(configdict)

如果您的问题是知道如何获得configdict,这取决于信息的来源。

如果您试图解析一个用户可编辑的配置文件,那么对于传统的.ini样式的文件,configparser模块可以很好地工作,并且文档中有一些链接可以解释如何处理其他流行格式。

如果您试图从命令行构建配置信息,请参见argparse

如果您想让环境变量与上述任何一个变量交互(例如,MYAPP_CONFIG可能会告诉您的configparser代码加载一个与正常配置文件不同的配置文件,或者MYAPP_CACHE_DIR可能会为--cachedir的命令行参数提供不同的默认值,那么您可以得到os.environ中的值,但是ha必须编写自己的代码来处理它们。