全局变量和局部变量
Python 中的变量并不是无论在哪个位置都可以访问的,访问权限取决于这个变量是在哪里赋值的。变量的作用域决定在哪一部分程序中可以访问哪个特定的变量。
根据变量作用域的不同,可把变量分为两种基本类型:全局变量 和 局部变量
全局变量:指在函数之外定义的变量,在程序执行全过程有效。一般没有缩进。
局部变量:指在函数之内定义的变量,仅在函数内部有效,当函数使用过后,变量从内存中释放(即变量将不再存在)。例如:
a = 1 # a 为全局变量
def calc():
b = a + 3 # b 为全局变量
print(b)
calc()
>>> 4
print(b)
>>> NameError Traceback (most recent call last)
<ipython-input-3-67e500defa1b> in <module>
----> 1 print(b)
NameError: name 'b' is not defined
n = 1
def calc(a,b):
n = b
return a + b
s = calc(5,4)
print(s,n)
>>> 9 1
从上面代码可知,函数 calc() 使用了变量 n ,且将参数 b 赋值给变量 n ,函数 calc() 有自己的内存空间,n = b 实际上是重新生成的局部变量,此时函数并没有将 n 看做全局变量 n 。当函数退出时,局部变量 n 被释放,全局变量的值没有改变。
如果要在函数中使用全局变量,只需要在函数内部的变量前加上关键字 global 。例如:
n = 1
def calc(a,b):
global n # 使用 global 声明 n 为全局变量
n = b
return a + b
s = calc(5,4)
print(s,n)
>>> 9 4
命名空间
命名空间的解释
作用域是指 Python 程序可以直接访问到的命名空间。
命名空间本质上是一个字典,它的键就是变量名,它的值就是变量的值。Python 使用命名空间来记录变量的轨迹。
在Python程序中的任何一个地方,都存在三个可用的命名空间。
(1)每个函数都有自己的命名空间(称作局部命名空间),它记录了函数中的变量,包括函数的参数和定义的局部变量。
(2)每个模块都有自己的命名空间(称作全局命名空间),它记录了模块中的变量,包括函数、类、其他导入的模块、模块级的变量和常量。
(3)每个模块都有可访问的内置命名空间,它存放着内建函数和异常。
命名空间的查找顺序
当一行代码要使用变量 x 的值时,Python 会到所有可用的命名空间去查找变量,其查找顺序如下。
(1) 局部命名空间——特指当前函数或类的方法。如果函数中定义了一个局部变量 x,Python 将使用这个变量,然后停止搜索。
(2)全局命名空间——特指当前的模块。如果模块中定义了一个名为 x 的变量、函数或类,Python 将使用它,然后停止搜索。
(3)内置命名空间——对每个模块都是全局的,作为最后的尝试,Python 将假设 x 是内建函数或变量。
(4)如果 Python 在这些命名空间中都找不到 x,它将放弃查找并引发一个NameError 异常,同时传递 There is no variable named‘x’ 这样一条信息。
当函数被调用时,创建一个局部命名空间,可以通过 globals() 和 locals() 两个内建函数判断某一名字属于哪个名称空间,locals() 是只读的,globals()不是。
def foo(arg, a):
x = 1
y = 'abc'
for i in range(5):
j = 2
k = i
print(locals())
foo(2,3)
>>> {'arg': 2, 'a': 3, 'x': 1, 'y': 'abc', 'i': 4, 'j': 2, 'k': 4}
locals() 实际上没有返回局部命名空间,它返回的是局部命名空间的一个拷贝,所以对它进行改变时,对局部命名空间的变量值并无影响。
var = globals()
print(var)
而 globals() 函数返回实际的全局命名空间,不是它的一个拷贝。所以对 globals() 函数所返回的 var 的任何改动都会直接影响到全局变量。