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一个新a
variables,初始化为shared_stuff.a
引用的任何shared_stuff.a
,并且这个新a
variables不会受到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(全局())