Python – 导入模块中全局variables的可见性

我碰到了一个在Python脚本中导入模块的墙。 我会尽我所能来形容这个错误,为什么我会遇到这个错误,为什么我要用这个特殊的方法来解决我的问题(我将在第二个问题中描述):

假设我有一个模块,在这个模块中定义了一些实用函数/类,这些实用函数/类是指在这个辅助模块将被导入的命名空间中定义的实体(让“a”成为这样一个实体):

模块1:

def f(): print a 

然后我有主程序,定义了“a”,我要导入这些程序:

 import module1 a=3 module1.f() 

执行该程序将触发以下错误:

 Traceback (most recent call last): File "Z:\Python\main.py", line 10, in <module> module1.f() File "Z:\Python\module1.py", line 3, in f print a NameError: global name 'a' is not defined 

过去也曾有类似的问题 (前两天)提出过几种解决办法,但我并不认为这些问题符合我的要求。 这是我特别的背景:

我试图做一个连接到MySQL数据库服务器的Python程序,并用GUI显示/修改数据。 为了清晰起见,我已经在一个单独的文件中定义了一大堆辅助/实用MySQL相关函数。 然而,它们都有一个公用variables,我最初是 utilities模块中定义的,它是MySQLdb模块中的游标对象。 我后来意识到,应该在主模块中定义游标对象(用于与数据库服务器通信), 以便主模块和导入其中的任何内容都可以访问该对象。

最终结果是这样的:

utilities_module.py:

 def utility_1(args): code which references a variable named "cur" def utility_n(args): etcetera 

而我的主要模块:

program.py:

 import MySQLdb, Tkinter db=MySQLdb.connect(#blahblah) ; cur=db.cursor() #cur is defined! from utilities_module import * 

然后,只要我尝试调用任何实用程序函数,就会触发前面提到的“全局名称未定义”错误。

一个特别的build议是在公用程序文件中有一个“from program import cur”语句,例如:

utilities_module.py:

 from program import cur #rest of function definitions 

program.py:

 import Tkinter, MySQLdb db=MySQLdb.connect(#blahblah) ; cur=db.cursor() #cur is defined! from utilities_module import * 

但这是循环导入或类似的东西,底线,它也崩溃了。 所以我的问题是:

我该如何在主模块中定义“cur”对象,这些对象被导入到辅助函数中?

感谢您的时间和最深的歉意,如果解决scheme已发布到别处。 我自己找不到答案,我的书里没有更多的技巧。

Python中的全局variables是全局 ,而不是所有的模块。 (很多人都被这个困惑了,因为在C语言中,除非明确地将其设置为static否则在所有实现文件中都是相同的。)

有不同的方法来解决这个问题,这取决于你的实际使用情况。


在走下这条路之前,问问自己这是否真的需要全球化。 也许你真的想要一个类,用f作为实例方法,而不仅仅是一个自由函数? 那么你可以做这样的事情:

 import module1 thingy1 = module1.Thingy(a=3) thingy1.f() 

如果你真的想要一个全局的,但它只是在那里被module1 ,设置在该模块。

 import module1 module1.a=3 module1.f() 

另一方面,如果a模块被大量模块所共享,就把它放在别的地方,然后让每个人都导入它:

 import shared_stuff import module1 shared_stuff.a = 3 module1.f() 

…和module1.py中:

 import shared_stuff def f(): print shared_stuff.a 

除非variables是一个常量,否则不要使用from导入。 from shared_stuff import a会创build一个新avariables,初始化为shared_stuff.a引用的任何shared_stuff.a ,并且这个新avariables不会受到shared_stuff.a赋值的影响。


或者,在极less数情况下,您确实需要将其作为一个真正的全球化领域,就像内build模块一样,将其添加到内置模块中。 Python 2.x和3.x的具体细节有所不同。 在3.x中,它的工作原理是这样的:

 import builtins import module1 builtins.a = 3 module1.f() 

一个函数使用它定义的模块的全局variables。例如,应该设置module1.a = 3 ,而不是设置a = 3 module1.a = 3 。 所以,如果你想在cur作为一个全局utilities_module ,可以设置utilities_module.cur

更好的解决scheme:不要使用全局variables。 将需要的variables传递给需要它的函数,或者创build一个类来将所有数据绑定在一起,并在初始化实例时传递它。

这篇文章只是对我遇到的Python行为的观察。 如果你做了同样的事情,也许你上面阅读的build议不适合你。

也就是说,我有一个包含全局/共享variables的模块(如上所示):

 #sharedstuff.py globaltimes_randomnode=[] globalist_randomnode=[] 

然后我有导入共享的东西的主要模块:

 import sharedstuff as shared 

和一些其他模块,实际上填充这些数组。 这些被主模块调用。 当退出这些其他模块,我可以清楚地看到数组被填充。 但是当他们在主模块中阅读时,他们是空的。 这对我来说很奇怪(嗯,我是Python的新手)。 但是,当我更改主模块中的sharedstuff.py的input方式时:

 from globals import * 

它的工作(数组被填充)。

只是在说'

作为一个解决方法,你可以考虑在外层设置环境variables,像这样。

main.py:

 import os os.environ['MYVAL'] = str(myintvariable) 

mymodule.py:

 import os print os.environ['MYVAL'] 

作为一个额外的预防措施,当模块内没有定义MYVAL时处理这种情况。

解决这个问题的最简单的方法是在模块中添加另一个函数,该函数将光标存储在模块的全局variables中。 那么所有其他的function也可以使用它。

模块1:

 cursor = None def setCursor(cur): global cursor cursor = cur def method(some, args): global cursor do_stuff(cursor, some, args) 

主程序:

 import module1 cursor = get_a_cursor() module1.setCursor(cursor) module1.method() 

由于全局variables是特定于模块的,因此可以将以下函数添加到所有导入的模块,然后使用它来:

  • 添加奇异variables(以字典格式)作为全局variables
  • 将你的模块全局转移到它。

addglobals = lambda x:globals()。update(x)

然后,你需要传递当前全局variables是:

导入模块

module.addglobals(全局())