70

在 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()

但是您永远不应该遇到两个具有相同名称的变量,并且需要在同一范围内使用它们的问题。

4

9 回答 9

90

Python 为程序员提供了大量的工具来自省运行环境。globals()只是其中之一,在调试会话中查看全局范围实际包含哪些对象非常有用。

我敢肯定,它背后的基本原理与locals()用于查看函数中定义的变量,或dir用于查看模块的内容或对象的属性的原理相同。

来自 C++ 背景,我可以理解这些东西似乎没有必要。在静态链接、静态类型的环境中,它们绝对会。在这种情况下,在编译时就知道哪些变量是全局变量,对象将拥有哪些成员,甚至另一个编译单元导出了哪些名称。

然而,在动态语言中,这些东西不是固定的。它们可以根据代码的导入方式甚至在运行时进行更改。至少出于这个原因,在调试器中访问此类信息可能是无价的。

于 2012-10-02T16:07:15.847 回答
41

当您需要使用函数的字符串名称调用函数时,它也很有用。例如:

def foo():
    pass

function_name_as_string = 'foo'

globals()[function_name_as_string]() # foo(). 
于 2013-09-23T17:46:34.623 回答
8

您可以将 and 的结果传递globals()locals(),evalexecfile命令__import__。这样做会为这些命令的工作创建一个受限环境。

因此,这些功能的存在是为了支持其他功能,这些功能受益于给定可能与当前上下文不同的环境。例如,您可以globals()在调用其中一个函数之前调用然后删除或添加一些变量。

于 2012-10-02T16:11:58.063 回答
6

globals()eval()——如果你想评估一些引用范围内变量的代码很有用,这些变量要么在全局变量中,要么在局部变量中。


稍微扩展一下,eval()内置函数将解释给它的一串 Python 代码。签名是: eval(codeString, globals, locals),你可以像这样使用它:

def foo():
    x = 2
    y = eval("x + 1", globals(), locals())
    print("y=" + y) # should be 3

这是有效的,因为解释器xlocals()变量的字典中获取值。您当然可以将自己的变量字典提供给 eval。

于 2012-10-02T15:47:35.123 回答
1

它在“声明性 python”中很有用。例如,在下面FooDefBarDef是用于定义一系列数据结构的类,然后某些包将这些数据结构用作其输入或配置。这使您在输入内容方面具有很大的灵活性,并且您无需编写解析器。

# 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 ...

PLY (Python-lex-yacc) http://www.dabeaz.com/ply/是通过从 python 模块收集一堆定义来获取其输入的包的一个示例 ——在这种情况下,对象主要是函数对象,但来自函数对象的元数据(它们的名称、文档字符串和定义顺序)也构成输入的一部分。这不是使用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 模块都很有用,可以更轻松地将项目添加到数据中,而无需维护引用。

于 2015-06-20T23:34:42.360 回答
0

它还可以用于从字符串中获取类 'classname' 的实例:

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)
于 2018-03-30T13:34:43.640 回答
0

如果您想导入刚刚构建的模块,这可能会很有用:

一个.py

[...]

def buildModule():
    [...code to build module...]
    return __import__("somemodule")

[...]

b.py

from a import buildModule

def setup():
   globals()["somemodule"] = buildModule()
于 2019-11-15T13:38:09.053 回答
0

我在答案中没有注意到任何关于使用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"
于 2021-03-29T14:28:25.240 回答
0

并不真地。Python 真正拥有的全局变量是模块范围的变量。

# a.py
print(globals())

import b
b.tt()
# b.py
def tt():
    print(globals())

运行python a.py,至少有两个输出globals()['__name__']不同。

Github 上的cpython中的代码显示了它。

于 2020-03-05T09:18:56.237 回答