Answers:
我不以任何方式,形状或形式认可该解决方案。但是,如果您将变量添加到__builtin__
模块中,则__builtin__
默认情况下,就如同所有其他包含- 的模块一样,都可以访问该变量。
a.py包含
print foo
b.py包含
import __builtin__
__builtin__.foo = 1
import a
结果是打印了“ 1”。
编辑:该__builtin__
模块可用作本地符号__builtins__
-这就是其中两个答案之间存在差异的原因。另请注意,__builtin__
它已builtins
在python3中重命名为。
hasattr(__builtin__, "foo")
。
如果您需要一个全局的跨模块变量,也许只需简单的全局模块级变量就足够了。
a.py:
var = 1
b.py:
import a
print a.var
import c
print a.var
c.py:
import a
a.var = 2
测试:
$ python b.py
# -> 1 2
实际示例:Django的global_settings.py(尽管在Django应用中,设置是通过导入对象使用的 django.conf.settings
)。
a.py
包含该main()
怎么办?有关系吗?
if __name__=="__main__"
在其中使用防护,以避免在导入时运行意外的代码。
id()
检查身份)
我认为在很多情况下它确实有意义,并且它简化了编程,使某些全局变量在多个(紧密耦合的)模块中广为人知。本着这种精神,我想详细说明一下由需要引用全局模块的模块导入的全局模块。
当只有一个这样的模块时,我将其命名为“ g”。在其中,我为每个要视为全局变量的变量分配默认值。在使用它们的每个模块中,我都不使用“ from g import var”,因为这只会导致局部变量,该局部变量仅在导入时才从g初始化。我以g.var和“ g”的形式进行大多数引用。不断提醒我,我正在处理其他模块可能访问的变量。
如果此类全局变量的值要在模块中的某些函数中频繁使用,则该函数可以创建本地副本:var = g.var。但是,重要的是要认识到对var的分配是本地的,并且全局g.var不能在不显式引用分配中的g.var的情况下进行更新。
请注意,您还可以让模块的不同子集共享多个这样的全局变量模块,以使事情得到更严格的控制。我对全局模块使用短名称的原因是为了避免由于出现它们而使代码过于混乱。仅凭少量经验,它们仅用1个或2个字符就变得足够易记。
当x尚未在g中定义时,仍然可以对gx进行赋值,然后另一个模块可以访问gx。但是,即使解释器允许,这种方法也不是那么透明,我会避免它。由于赋值的变量名称中有错字,仍有可能意外地在g中创建新变量。有时,对dir(g)的检查对于发现此类事故可能引起的任何意外名称很有用。
全局变量通常不是一个好主意,但是您可以通过分配给__builtins__
:
__builtins__.foo = 'something'
print foo
同样,模块本身是可以从任何模块访问的变量。因此,如果您定义一个名为的模块my_globals.py
:
# my_globals.py
foo = 'something'
然后,您也可以在任何地方使用它:
import my_globals
print my_globals.foo
__builtins__
通常,使用模块而不是修改模块是执行此类全局操作的更干净的方法。
这听起来像修改__builtin__
名称空间。去做吧:
import __builtin__
__builtin__.foo = 'some-value'
不要__builtins__
直接使用(请注意额外的“ s”)-显然这可以是字典或模块。感谢ΤZnΩΤZΙΟΥ指出这一点,更多内容请点击这里。
现在 foo
可在任何地方使用。
我不建议一般这样做,但是使用此方法取决于程序员。
分配它必须按照上面的步骤进行,只是设置foo = 'some-other-value'
只会在当前名称空间中进行设置。
我将此用于几个内置的原始函数,我觉得它们确实缺少了。一个示例是具有与filter,map,reduce相同的用法语义的find函数。
def builtin_find(f, x, d=None):
for i in x:
if f(i):
return i
return d
import __builtin__
__builtin__.find = builtin_find
一旦运行(例如,通过在入口点附近导入),所有模块就可以使用find(),显然,它是内置的。
find(lambda i: i < 0, [1, 3, 0, -5, -10]) # Yields -5, the first negative.
注意:当然,您可以使用过滤器和另一条线来测试零长度,或者使用减少一种奇怪的线来执行此操作,但是我始终觉得这很奇怪。
我可以使用字典来实现跨模块的可修改(或可变)变量:
# in myapp.__init__
Timeouts = {} # cross-modules global mutable variables for testing purpose
Timeouts['WAIT_APP_UP_IN_SECONDS'] = 60
# in myapp.mod1
from myapp import Timeouts
def wait_app_up(project_name, port):
# wait for app until Timeouts['WAIT_APP_UP_IN_SECONDS']
# ...
# in myapp.test.test_mod1
from myapp import Timeouts
def test_wait_app_up_fail(self):
timeout_bak = Timeouts['WAIT_APP_UP_IN_SECONDS']
Timeouts['WAIT_APP_UP_IN_SECONDS'] = 3
with self.assertRaises(hlp.TimeoutException) as cm:
wait_app_up(PROJECT_NAME, PROJECT_PORT)
self.assertEqual("Timeout while waiting for App to start", str(cm.exception))
Timeouts['WAIT_JENKINS_UP_TIMEOUT_IN_SECONDS'] = timeout_bak
启动时test_wait_app_up_fail
,实际的超时时间为3秒。
我想知道是否有可能避免使用全局变量的某些缺点(请参见例如http://wiki.c2.com/?GlobalVariablesAreBad通过使用类命名空间而不是全局/模块命名空间来传递变量值) 。以下代码表明这两种方法本质上是相同的。如下所述,使用类名称空间有一点优势。
以下代码片段还显示,可以在全局/模块名称空间和类名称空间中动态创建和删除属性或变量。
wall.py
# Note no definition of global variables
class router:
""" Empty class """
我称此模块为“墙”,因为它是用来反弹变量的。它将用作临时定义空类“路由器”的全局变量和类范围属性的空间。
source.py
import wall
def sourcefn():
msg = 'Hello world!'
wall.msg = msg
wall.router.msg = msg
该模块导入wall并定义一个函数sourcefn
,该函数定义消息并通过两种不同的机制发出消息,一种通过全局机制,一种通过路由器函数。请注意,变量wall.msg
和wall.router.message
是在此处首次在其各自的名称空间中定义。
目的地
import wall
def destfn():
if hasattr(wall, 'msg'):
print 'global: ' + wall.msg
del wall.msg
else:
print 'global: ' + 'no message'
if hasattr(wall.router, 'msg'):
print 'router: ' + wall.router.msg
del wall.router.msg
else:
print 'router: ' + 'no message'
该模块定义了一个函数destfn
,该函数使用两种不同的机制来接收源发出的消息。它允许变量“ msg”可能不存在。destfn
在显示变量后也将删除它们。
main.py
import source, dest
source.sourcefn()
dest.destfn() # variables deleted after this call
dest.destfn()
该模块依次调用先前定义的函数。第一次调用dest.destfn
变量后wall.msg
,wall.router.msg
不再存在。
该程序的输出为:
全球:您好,世界!
路由器:世界您好!
全局:无消息
路由器:无消息
上面的代码片段表明,模块/全局机制和类/类变量机制基本相同。
如果要共享许多变量,则可以通过使用多个wall类型的模块(例如wall1,wall2等)或通过在单个文件中定义多个路由器类型的类来管理名称空间污染。后者稍微更整洁,因此也许代表了使用类变量机制的边际优势。