在Python中使用globals()函数的原因是什么?它只返回全局变量的字典,这些变量已经是全局的,因此它们可以在任何地方使用......我只是出于好奇,试图学习python。
def F():
global x
x = 1
def G():
print(globals()["x"]) #will return value of global 'x', which is 1
def H():
print(x) #will also return value of global 'x', which, also, is 1
F()
G()
H()
我真的看不出这里的意义吗?我唯一需要它的时候,是如果我有局部和全局变量,它们的名字都相同
def F():
global x
x = 1
def G():
x = 5
print(x) #5
print(globals()["x"]) #1
F()
G()
但是,您永远不应该遇到两个同名变量的问题,并且需要在同一范围内使用它们。
Python 为程序员提供了大量用于内省运行环境的工具。globals()
只是其中之一,在调试会话中查看全局范围实际包含的对象非常有用。
我敢肯定,它背后的基本原理与使用locals()
查看函数中定义的变量或使用dir
查看模块的内容或对象的属性相同。
来自C++背景,我可以理解这些事情似乎没有必要。在静态链接、静态类型的环境中,它们绝对会如此。在这种情况下,在编译时确切地知道哪些变量是全局的,对象将具有哪些成员,甚至另一个编译单元导出的名称。
然而,在动态语言中,这些东西不是固定的;它们可能会根据代码的导入方式而改变,甚至在运行时。至少出于这个原因,在调试器中访问此类信息可能是非常宝贵的。
当您需要使用函数的字符串名称调用函数时,它也很有用。例如:
def foo():
pass
function_name_as_string = 'foo'
globals()[function_name_as_string]() # foo().
您可以将globals()
和locals()
的结果传递给eval
、execfile
和__import__
命令。这样做会为这些命令创建一个受限制的环境。
因此,这些函数的存在是为了支持其他函数,这些功能受益于给定可能与当前上下文不同的环境。例如,您可以调用globals()
然后在调用其中一个函数之前删除或添加一些变量。
globals()
对eval()
很有用 - 如果要计算一些引用作用域中变量的代码,这些变量将位于全局或局部变量中。
为了扩展一点,eval()
内置函数将解释提供给它的一串 Python 代码。签名是:eval(codeString, globals, locals)
,你会这样使用它:
def foo():
x = 2
y = eval("x + 1", globals(), locals())
print("y=" + y) # should be 3
这是有效的,因为解释器从变量的locals()
字典中获取x
的值。当然,您可以向 eval 提供自己的变量字典。
它在"声明式python"中很有用。例如,在下面的FooDef
和BarDef
中,类用于定义一系列数据结构,然后由某个包用作其输入或配置。这使您在输入内容方面具有很大的灵活性,并且您无需编写解析器。
# FooDef, BarDef are classes
Foo_one = FooDef("This one", opt1 = False, valence = 3 )
Foo_two = FooDef("The other one", valence = 6, parent = Foo_one )
namelist = []
for i in range(6):
namelist.append("nm%03d"%i)
Foo_other = FooDef("a third one", string_list = namelist )
Bar_thing = BarDef( (Foo_one, Foo_two), method = 'depth-first')
请注意,此配置文件使用循环来构建名称列表,这些名称列表是Foo_other
配置的一部分。因此,这种配置语言带有一个非常强大的"预处理器",以及一个可用的运行时库。如果您想查找复杂的日志,或者从 zip 文件中提取内容并对其进行 base64 解码,作为生成配置的一部分(当然,对于输入可能来自不受信任的来源的情况,不建议使用此方法......
该软件包使用如下所示的内容读取配置:
conf_globals = {} # make a namespace
# Give the config file the classes it needs
conf_globals['FooDef']= mypkgconfig.FooDef # both of these are based ...
conf_globals['BarDef']= mypkgconfig.BarDef # ... on .DefBase
fname = "user.conf"
try:
exec open(fname) in conf_globals
except Exception:
...as needed...
# now find all the definitions in there
# (I'm assuming the names they are defined with are
# significant to interpreting the data; so they
# are stored under those keys here).
defs = {}
for nm,val in conf_globals.items():
if isinstance(val,mypkgconfig.DefBase):
defs[nm] = val
因此,最后进入正题,如果您想按程序铸造一系列定义,那么在使用这样的包时,globals()
很有用:
for idx in range(20):
varname = "Foo_%02d" % i
globals()[varname]= FooDef("one of several", id_code = i+1, scale_ratio = 2**i)
这相当于写出
Foo_00 = FooDef("one of several", id_code = 1, scale_ratio=1)
Foo_01 = FooDef("one of several", id_code = 2, scale_ratio=2)
Foo_02 = FooDef("one of several", id_code = 3, scale_ratio=4)
... 17 more ...
通过从 python 模块收集一堆定义来获取其输入的包的一个示例是 PLY (Python-lex-yacc) http://www.dabeaz.com/ply/- 在这种情况下,对象主要是函数对象,但来自函数对象的元数据(它们的名称、文档字符串和定义顺序)也构成了输入的一部分。这不是使用globals()
的好例子。此外,它是通过"配置"导入的 - 后者是普通的python脚本 - 而不是相反。
我在我参与的一些项目中使用了"声明式python",并且在为这些项目编写配置时有机会使用globals()
。你当然可以争辩说,这是由于配置"语言"设计方式的弱点。以这种方式使用globals()
不会产生非常明确的结果;只是可能比写出十几个几乎相同的陈述更容易维护的结果。
您还可以使用它根据变量的名称在配置文件中赋予变量意义:
# All variables above here starting with Foo_k_ are collected
# in Bar_klist
#
foo_k = [ v for k,v in globals().items() if k.startswith('Foo_k_')]
Bar_klist = BarDef( foo_k , method = "kset")
此方法对于任何定义大量表和结构的 python 模块都很有用,可以更轻松地向数据添加项,而无需维护引用。
它还可用于从 字符串:
class C:
def __init__(self, x):
self.x = x
print('Added new instance, x:', self.x)
def call(str):
obj = globals()[str](4)
return obj
c = call('C')
print(c.x)
如果您想导入刚刚构建的模块,这可能会很有用:
a.py
[...]
def buildModule():
[...code to build module...]
return __import__("somemodule")
[...]
b.py
from a import buildModule
def setup():
globals()["somemodule"] = buildModule()
不是真的。Python真正具有的全局变量是模块范围的变量。
# a.py
print(globals())
import b
b.tt()
# b.py
def tt():
print(globals())
运行python a.py
,至少两个输出globals()['__name__']
是不同的。
Github上的cpython代码显示了它。
我在答案中没有注意到任何关于使用globals()
来检查您是否设置了值的信息。也许您只在调试或忘记设置值并希望避免出现异常时才设置值。尽管在某些情况下locals()
可能是更好的解决方案,以避免访问全局范围并仅访问本地范围。
# DEBUG = True
if 'DEBUG' in globals():
print(f'We found debug flag and it has value {DEBUG}.')
else:
print(f'Debug flag was not found.')
您也可以将其与get()
结合使用,以在找不到变量的情况下设置默认值
# VARIABLE = "Value of var"
my_var = globals().get("VARIABLE", "Value was not found")
print(my_var) # Prints: "Value was not found"
print(VARIABLE) # Raises NameError
VARIABLE = "Value of var"
my_var = globals().get("VARIABLE", "Value was not found")
print(my_var) # prints: "Value of var"
print(VARIABLE) # prints: "Value of var"
它允许您访问、调用、(重新)定义当前模块范围内的全局变量,方法是在存储它们的字典中查找它们。
例如,您可能需要调用多个名称为func1
、func2
、func3
等的函数。 一种方法是通过在 for 循环中传递字符串f'func_{i}'
来迭代globals()
,而不是手动键入它们:
def func1():
return 1
def func2():
return 2
def func3():
return 3
for i in range(1, 4):
print(globals()[f'func{i}']())
在此处查看示例(底部单元格)