python中globals()的原因是什么?

Reason for globals() in Python?

在python中使用globals()函数的原因是什么?它只返回全局变量的字典,这些变量已经是全局的,所以它们可以在任何地方使用…我只是好奇地问,想学Python。

1
2
3
4
5
6
7
8
9
10
11
12
13
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()

我真的看不到这一点?我唯一需要它的时间是,如果我有局部变量和全局变量,它们都有相同的名称。

1
2
3
4
5
6
7
8
9
10
11
def F():
    global x
    x = 1

def G():
    x = 5
    print(x) #5
    print(globals()["x"]) #1

F()
G()

但是您不应该遇到两个同名的变量的问题,并且需要在同一范围内同时使用这两个变量。


Python为程序员提供了大量的工具来反思运行环境。这只是其中的一个,在一次解析会议上,它可以非常有用地看到全球范围内实际包含的目标。

我敢肯定,理性的背后是与使用EDOCX1〕〔5〕一样的,目的是看到变量在一个函数中定义,或使用dir来看到一个模块的内容或一个物体的属性。

从一个C+++背景来看,我可以理解,这些东西看起来不需要。在一个静态链接中,静态类型的环境中,它们将是绝对的。在这种情况下,在准确的时间编译变量是什么是全球性的,而一个物体的成员将拥有什么,甚至通过另一个编译单元导出什么名称。

在动态语言中,这些东西是不固定的;它们可以根据何种代码被导入而改变,或者甚至在运行时改变。由于这一原因,在一个解调器中获得这一信息的机会是不可估价的。


当你需要用函数字符串命名函数时,它也很有用。For example:

ZZU1


你可以把globals()locals()的结果传达给evalexecfile__import__指挥官。为这些命令创造一种限制性的环境,以便在那里工作。

因此,这些函数存在于支持其他函数的过程中,这些函数的效益来自于当前环境的不同潜力。例如,你可以叫globals(),然后在呼叫其中一个函数之前去除或添加一些变量。


如果你想评价一些参照范围内变量的代码,那么这些变量会出现在全球或地方。

为了扩展位,建筑物功能将解释给它的一条Python码。签名是:EDOCX1&3,你可以用它这样:

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

这篇作品,因为解释者从x中获得了locals()的价值。你可以用你自己的变量口令来评价。


它还可以用于从字符串:

1
2
3
4
5
6
7
8
9
10
11
12
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)

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

1
2
3
4
5
6
7
8
9
10
11
12
# 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对其进行解码,作为生成配置的一部分(当然,对于输入可能来自不受信任的源的情况,不建议使用这种方法…)

该包使用如下内容读取配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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()非常有用:

1
2
3
for idx in range(20):
    varname ="Foo_%02d" % i
    globals()[varname]= FooDef("one of several", id_code = i+1, scale_ratio = 2**i)

这相当于写出

1
2
3
4
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/—在这种情况下,对象主要是函数对象,但是来自函数对象(它们的名称、docstring和定义顺序)的元数据也构成了输入的一部分。这不是使用globals()的好例子。另外,它是通过"配置"导入的,后者是一个普通的Python脚本,而不是通过另一种方式导入的。

我在一些项目中使用了"声明性python",并且在为这些项目编写配置时有机会使用globals()。您可以肯定地说,这是由于配置"语言"的设计方式存在缺陷。以这种方式使用globals()不会产生非常清晰的结果;只是结果可能比写出一打几乎相同的语句更容易维护。

您还可以使用它根据变量的名称在配置文件中赋予变量重要性:

1
2
3
4
5
# 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模块都很有用,这样可以更容易地向数据添加项,而不必维护引用。