Python具有静态作用域,变量的作用域由它定义的位置决定,而与调用的位置无关。
1 a = 2
2
3 def f():
4 a = 2
第一行的a的作用域是全局作用域,作用于定义位置后面的所有位置。
第四行的a的作用域是局部作用域,作用于f函数里。
Python能够形成局部作用域的只有函数与类,其他语句不形成局部作用域。
函数与类的局部作用域
1 def f():
2 a = 1
3 class A:
4 b = 2
5 if 1 == 1:
6 c = 3
7 for _ in range(1):
8 d = 4
9 while True:
10 e = 5
11 break
12 print(c, d, e)
13 try:
14 print(a)
15 except Exception as e:
16 print(e)
17 try:
18 print(b)
19 except Exception as e:
20 print(e)
输出结果
1 3 4 5
2 name 'a' is not defined
3 name 'b' is not defined
python动态运行时,每个作用域都有三个名字空间:由局部变量组成的local名字空间,由全局变量组成的global名字空间,以及python内建模块的builtins名字空间,在查询一个变量时,搜索顺序为local->global->builtins,即局部变量屏蔽全局变量,全局变量屏蔽内建变量。
python的global名字空间是动态的,即每遇到一个赋值语句(def与class也属于赋值语句),global名字空间都可能发生变化。
global名字空间的动态变化
1 print(dir())
2 a = 1
3 print(dir())
4 b = 2
5 print(dir())
输出结果
1 ['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
2 ['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'a']
3 ['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'b']
从输出结果可以看出,global名字空间是动态增加的。
这意味着,虽然位于global名字空间的变量叫做全局变量,它的作用范围也不是全局位置,它只作用于第一次赋值之后的位置。因为只有在变量赋值初始化的时候,它才会被加入到global名字空间中。
函数和类搜索的global名字空间是调用位置的global名字空间,与定义位置无关
1 def f():
2 print(a)
3
4 try:
5 f()
6 except Exception as e:
7 print(e)
8
9 a = 2
10 f()
输出结果
1 name 'a' is not defined
2 2
函数f打印全局变量a,a在第9行定义。在第五行调用f的时候,a不在global名字空间中,所以会输出错误信息,在第十行再次调用函数f时,a已经加入了global名字空间,所以能够打印出a。
python为了提高效率,local名字空间是静态实现的,因为对于一个函数来说,它所包含的局部变量是明确已知的。
函数的local名字空间是静态的
1 a = 4
2
3 def f():
4 try:
5 print(a)
6 except Exception as e:
7 print(e)
8 a = 1
9
10 f()
输出结果
1 local variable 'a' referenced before assignment
在打印a的时候,在local名字空间中找到了a,但是这时候a并没有赋值初始化,所以抛出异常。这也说明了local名字空间与global名字空间不同,它会在一开始就把所有的局部变量加入到名字空间中。
总结:
1. python是静态作用域,变量初始化的位置决定了它的作用域,而与变量调用的位置无关
2. global名字空间是动态的,不同位置的global名字空间不同,local名字空间是静态的,局部变量在整个局部作用域内可见。