在Python中,有时会用到如题的变量,实现某些功能会很方便,但是极易出错!所以,有必要对他们进行深刻了解,以免出现莫名其妙的错误。在分析他们之前,必须先了解python的名字空间(命名空间)name space的概念。
一、name space 名字空间(命名空间)
简而言之,名字空间是名称的集合,可以理解为python中已定义的每个名称到对应对象的映射。命名空间实际上是一个字典,它的键就是字符串形式的变量名字,它的值就是变量的实际值,您可以像对待dictionary一样访问名字空间!不同的命名空间可以在给定时间共存,但完全隔离,因此不同模块中可能存在的相同名称而不会产生冲突!
每个函数的名字空间,叫做“局部名字空间”,它记录着函数的变量,包括函数的参数和局部定义的变量。
每个模块的名字空间,叫做“全局名字空间”,它记录着模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
还有就是“内置名字空间”,程序的任何模块均可访问它,它存放着python的内置函数和异常。
当代码要使用变量var时,Python 会到所有可用的名字空间去查找变量,按照如下顺序:
(1)局部名字空间:特指当前函数或类的方法,一旦找到局部变量var或参数var,Python就返回之;
(2)全局名字空间:特指当前的模块,一旦找到某个变量、函数或类var,Python就返回之;
(3)内置名字空间:作为最后的尝试,Python 将假设var是内置函数或变量;
(4)如果在这些名字空间都找不到,Python将引发NameError 异常,同时报错 There is no variable named 'var'
当两个名字(例如变量名)发生重叠式,按照第一部分说的,局部名字优先!所以,在函数体内局部变量将覆盖全局变量,除非显式地用global var加以声明才行!
二、局部变量和全局变量
当两个名字(如变量名)发生重叠式,按照第一部分说的,局部名字优先!所以,在函数体内局部变量将覆盖全局变量,除非显式地用global var加以声明才行!具体可见下面的示例。
记住2点:一是尽量不用全局变量!二是必要时定义一个类来保存全局变量::
- 简单时就直接访问成员变量;
- 需要控制时就声明为私有变量,用成员函数访问和修改;
- 多组多线程分开共享时就每组new一个新实例即可。
对于复杂的多线程、跨模块的全局变量,可以参考这篇文章:
三、内置函数globals()与locals()
局部名字空间可以通过Python内置的 locals()函数来访问,全局名字空间 (模块级别) 可以通过内置 globals()函数来访问。这两个函数提供基于字典的访问局部变量和全局变量的方式。其中,globals()可以修改,而locals()是只读的,不可修改。原因是:
locals()实际上没有返回局部名字空间,它返回的是一个拷贝。所以,对它进行修改,变化的仅仅是拷贝,而局部名字空间中的实际变量值并无变化。
globals()返回的是实际的全局名字空间,而不是一个拷贝。所以,对它进行的任何修改都会直接影响到全局变量的值。
一个问题:from module import function和 import module 之间的不同?
使用 import module,模块虽被导入但是它还保持着自已的名字空间,这就是为什么您需要使用模块名来访问它的函数或属性: module.function()的原因;
使用 from module import func,实际上是从另一个模块中将指定的函数和属性导入到您自己的名字空间,这时就可以直接访问它们function(),而不需要引用它们所来源的模块!
四、代码示例
1.示例1:使用globals()自动创建双重列表。该方法的返回值是三个变量,但方法中没有明确定义这三个变量,实质上他们被隐式地声明为全局变量了。
def fun():
glist = ['aa', 'bb', 'cc'] # 注意列表的名字,尽管它是局部变量。后期会用于生成全局变量!
for i in glist:
globals()[i] = {} # 先迭代自动创建变量,花括号是集合或者字典
globals()[i]['data'] = [] # 每个变量自动创建为键为‘data’的字典,其中对应的值为列表
globals()[i]['data'].append([])
# data对应的值为列表,列表中包含子列表,通过append添加元素(空列表)
globals()[i]['data'].append([])
globals()[i]['data'][0].append('hello') # 通过下标确定子列表,追加元素
globals()[i]['data'][0].append('world') # 通过下标确定子列表,追加元素
return aa, bb, globals()['cc']
# 这3个变量都已成为全局变量。编译器对aa、bb告警,但是不影响执行;cc因显式标注故不报警。
n,w,t=fun()
print(str(n)+','+str(w)+','+str(t),"\n")
输出:
{'data': [['hello', 'world'], []]},{'data': [['hello', 'world'], []]},{'data': [['hello', 'world'], []]}
2.示例2: 对globals()与locals()修改能力的展示。
global_y = 1 # 定义全局变量
def foo(arg):
local_x = 0
print(locals(), "local_x=", local_x)
locals()['local_x'] = 1 # 修改的是局部名字空间的拷贝,实际局部名字空间中的变量不受影响。
print(locals(), "local_x=", local_x)
foo(3)
print(globals())
print('global_y=', global_y)
globals()["global_y"] = 2 # globals()返回的是实际的全局名字空间,修改变量global_y的值
globals()["global_z"] = 1001 # globals()新增了一个的全局变量global_z
print(globals())
print('global_y=', global_y)
print('global_z=', global_z) # 尽管告警但不影响执行!改成globals()["global_z"]就不告警了。
输出:
{'arg': 3, 'local_x': 0} local_x= 0
{'arg': 3, 'local_x': 0} local_x= 0
{'__name__': '__main__', '__doc__': 'This is my first python program!', '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000192EBCA0880>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:/Users/User/Desktop/Shamir secret sharing/Shamir secret sharing/tst', '__cached__': None, 'global_y': 1, 'fun': <function fun at 0x00000192EC011550>, 'foo': <function foo at 0x00000192EC0115E0>, 'aa': {'data': [['hello', 'world'], []]}, 'bb': {'data': [['hello', 'world'], []]}, 'cc': {'data': [['hello', 'world'], []]}, 'n': {'data': [['hello', 'world'], []]}, 'w': {'data': [['hello', 'world'], []]}, 't': {'data': [['hello', 'world'], []]}}
global_y= 1
{'__name__': '__main__', '__doc__': 'This is my first python program!', '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000192EBCA0880>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:/Users/User/Desktop/Shamir secret sharing/Shamir secret sharing/tst', '__cached__': None, 'global_y': 2, 'fun': <function fun at 0x00000192EC011550>, 'foo': <function foo at 0x00000192EC0115E0>, 'aa': {'data': [['hello', 'world'], []]}, 'bb': {'data': [['hello', 'world'], []]}, 'cc': {'data': [['hello', 'world'], []]}, 'n': {'data': [['hello', 'world'], []]}, 'w': {'data': [['hello', 'world'], []]}, 't': {'data': [['hello', 'world'], []]}, 'global_z': 1001}
global_y= 2
global_z= 1001
未完,待续……