Python 之变量作用域
2017-06-04
什么是作用域
作用域, 直观的概念就是作用范围, 比如变量的可用范围, 方法的可用范围, 类的可用范围,
在这个范围内, 我们可以访问这个对象(变量/方法/类),
简而言之, 作用域是对变量/方法/类的访问的范围的限制
变量作用域
变量作用域
就是对变量访问的范围的限制,
比如, 定义了某个变量a, 那么在什么地方可以访问这个变量呢, 以下是我的总结
函数作用域
这是最直观的作用域, 我们在函数内定义了一个变量, 在这个函数内可以直接访问, 在函数外则访问不到
def test_a():
l_name = 'Yi_Zhi_Yu'
print('test_a l_name:{}'.format(l_name))
test_a() # test_a l_name:Yi_Zhi_Yu
以上代码, 运行时能输出的变量l_name
处于 test_a
这个函数的函数作用域内, 在函数外不可访问
def test_a():
l_name = 'Yi_Zhi_Yu'
print('test_a l_name:{}'.format(l_name))
test_a() # test_a l_name:Yi_Zhi_Yu
print(l_name)
报错
test_a l_name:Yi_Zhi_Yu
Traceback (most recent call last):
File "/xxx/path/a.py", line 17, in <module>
print(l_name)
NameError: name 'l_name' is not defined
提示 l_name
未定义, 但函数内的变量依然打印出来了
文件作用域
a.py
文件中
f_name = 'tony'
def test_a():
l_name = 'Yi_Zhi_Yu'
print('test_a l_name:{}'.format(l_name))
print('test_a f_name:{}'.format(f_name))
test_a()
#print(l_name)
print('file f_name: {}'.format(f_name))
输出如下
test_a l_name:Yi_Zhi_Yu
test_a f_name:tony
file f_name: tony
文件中定义的变量, 在函数内和函数外都访问到了
那么, 假如变量在某个函数内修改了, 那么这个变量在函数外会发生什么变化呢
f_name = 'tony'
def test_a():
l_name = 'Yi_Zhi_Yu'
print('test_a l_name:{}'.format(l_name))
print('test_a f_name:{}'.format(f_name))
f_name = 'tony2' # 在这里对文件作用域内的变量(f_name)做修改
print('test_a new f_name:{}'.format(f_name))
test_a()
# print(l_name)
print('file f_name: {}'.format(f_name))
运行时确报错了
test_a l_name:Yi_Zhi_Yu
Traceback (most recent call last):
File "/xxx/path/a.py", line 18, in <module>
test_a()
File "/xxx/path/a.py", line 14, in test_a
print('test_a f_name:{}'.format(f_name))
UnboundLocalError: local variable 'f_name' referenced before assignment
而且提示的出错的位置是在函数内还未对f_name
做修改的时候, 提示的错误是 local variable 'f_name' referenced before assignment
,
看起来是打印了一个未定义的局部变量
可以看出, 定义的文件作用域内的变量是不允许直接修改的, 否则会被当做函数的局部变量
那么如果在函数内重新定义了该变量, 在函数外的同名变量又会怎么样呢
f_name = 'tony'
def test_a():
l_name = 'Yi_Zhi_Yu'
print('test_a l_name:{}'.format(l_name))
# print('test_a f_name:{}'.format(f_name)) # 去掉这里
f_name = 'tony2'
print('test_a new f_name:{}'.format(f_name))
test_a()
# print(l_name)
print('file f_name: {}'.format(f_name))
输出如下:
test_a l_name:Yi_Zhi_Yu
test_a new f_name:tony2
file f_name: tony
可以看出来, 在函数内部重新定义的变量, 就被视为局部变量, 影响的也只是所在的局部变量作用域
, 并不会影响文件作用域
, 甚至是全局作用域
全局作用域
如果我们在另一个模块文件b.py
中打印a.py
里的变量会怎么样
import a
print('b.py a.f_name: {}'.format(a.f_name))
如果是通过模块引用的方式, 如上, 结果可以正常输出
test_a l_name:Yi_Zhi_Yu
test_a new f_name:tony2
file f_name: tony
b.py a.f_name: tony # 这里就是b.py里的a.f_name 输出
那如果是直接print(f_name)
呢
import a
print('b.py a.f_name: {}'.format(a.f_name))
print('b.py f_name: {}'.format(f_name))
报错了
test_a l_name:Yi_Zhi_Yu
test_a new f_name:tony2
file f_name: tony
b.py a.f_name: tony
Traceback (most recent call last):
File ""/xxx/path/b.py", line 8, i <module>
print('b.py f_name: {}'.format(f_name))
NameError: name 'f_name' is not defined
看来, a.py
模块文件中的文件作用域的变量是不能在该文件之外直接访问的
那有没有什么方式可以实现呢
也许有人说用global
关键字, 我们来试一下
import a
print('b.py a.f_name: {}'.format(a.f_name))
global f_name
print('b.py f_name: {}'.format(f_name))
运行b.py, 也是同样的错误
看来, python 中是不允许跨文件(模块)的变量直接访问(print(f_name)
)的, 必须通过模块引用的方式print(a.f_name)
python 的全局作用域也仅限于单个的模块文件中, 即所谓的全局变量
就是单个模块文件内的全局变量
那么global
关键字是如何使用的呢
global 关键字
其实在上面的一个场景(文件作用域)中, 我们想在函数中对模块文件中的全局变量
f_name
进行修改和打印, 但报错了,
因为当在函数内对全局变量做修改时, 该变量就被当成了局部变量, 而局部变量需要先定义才能使用
而且在函数中对f_name
做修改后, 并不会影响函数外的f_name
那假如我们确实想在函数内修改全局变量怎么办?
这个时候global
就派上用场了
f_name = 'tony'
def test_a():
l_name = 'Yi_Zhi_Yu'
print('test_a l_name:{}'.format(l_name))
print('test_a f_name:{}'.format(f_name))
global f_name # 这里使用global关键字
f_name = 'tony2'
print('test_a new f_name:{}'.format(f_name))
test_a()
# print(l_name)
print('file f_name: {}'.format(f_name))
运行a.py
输出如下
/xxx/path/a.py:15: SyntaxWarning: name 'f_name' is used prior to global declaration
global f_name
test_a l_name:Yi_Zhi_Yu
test_a f_name:tony
test_a new f_name:tony2
file f_name: tony2 # 函数外的全局变量
我们可以看到, 函数外的全局变量f_name
也被更改了
注意, 上面还有一个SyntaxWarning
, 提示在使用global
关键字前, f_name
被优先当做全局变量使用了, 当然, 这里不推荐这么使用, 如果真的有必要, 在test_a
的第一行就使用global f_name
即可