目录
一、变量作用域
二、全局变量&局部变量
2.1 global 和nonlocal关键字
一、变量作用域
python中,变量不是在哪里都可以访问的,访问权限决定于变量是在哪里被赋值的。变量作用域决定了哪一部分程序可以访问哪些特定的变量。python的作用域一共分为四种:
- L(local) 局部作用域
- E(enclosing) 闭包函数外的函数中
- G(global) 全局作用域
- B(built-in) 内建作用域
程序查找变量的规则为:L-->E-->G-->B ,通过位置怎么去判断变量属于那种变量,请看下代码:
x=range(0,10) #内建作用域
spam=10 #全局作用域
def outer():
eggs=10 # 闭包函数外的函数中
def inner():
apple=2 #局部作用域
那什么时候程序会引入新的作用域呢?python中只有类、模块、函数才会引入新的作用域。其他的代码块(如 if/elif/else , for/while)等是不会引入新的作用域的,语句内定义的变量,外部也可以访问,如下代码:
if True:
msg='hello world'
print(msg) #hello world
这段代码,变量msg在if语句块中,但是外部也可以访问。
二、全局变量&局部变量
全局变量:变量定义在函数外部。全局作用域,是程序开始的时候创建的,程序终止,全局作用域就会被销毁,它的所有变量就会被丢弃。
局部变量:变量定义在函数内部。函数被调用,或者被另一个函数调用时,局部作用域就创建了,该函数返回时,局部作用域就会被销毁。
两者之间的关系:全局作用域中程序不能使用局部作用域中的变量,但是局部作用域中可以使用全局变量。同时局部作用域不可以使用其他局部作用域中的变量。
请看实例:
def spam():
eggs=99
bacon()
print(eggs)
def bacon():
ham=101
eggs=0
spam() #99
实例分析:为什么输出的是99而不是0呢?
在程序开始运行时, spam()函数被调用, 创建了一个局部作用域。局部变量eggs被赋值为 99。然后 bacon()函数被调用, 创建了第二个局部作用域。多个局部作用域能同时存在。在这个新的局部作用域中, 局部变量 ham 被赋值为 101。局部变量 eggs(与 spam()的局部作用域中的那个变量不同) 也被创建, 并赋值为 0。当 bacon()返回时, 这次调用的局部作用域被销毁。程序执行在 spam()函数中继续, 打印出 eggs 的值。因为 spam()调用的局部作用域仍然存在, eggs 变量被赋值为 99。
要点在于,一个函数中的局部变量完全与其他函数中的局部变量分隔开来。
2.1 global 和nonlocal关键字
当局部作用域想要修改全局作用域中的变量时,就需要用到global和nonlocal关键字了。
如果要修改全局变量,要用到global管家字:
#全局变量可以在局部变量中读取
def spam():
global eggs
print(eggs)
eggs=10
print(eggs)
eggs=42
spam() # 42 10
如果要修改嵌套作用域(enclosing作用域,就是外层的非全局作用域)则需要nonlocal关键字,如下:
def outer():
num=10
def inner():
nonlocal num #nonlocal关键字声明
num=99
print(num)
inner()
print(num)
outer() # 99 99
还有一种情况,通过参数传递来使用全局变量,如下实例:
a=10
def test():
a=a+1
print(a)
test()
运行后会报错:
Traceback (most recent call last):
File "E:/IdeaProjects/Demi/20180904-1.py", line 151, in <module>
test()
File "E:/IdeaProjects/Demi/20180904-1.py", line 149, in test
a=a+1
UnboundLocalError: local variable 'a' referenced before assignment
报错为局部作用域引用错误。但是可以将全局变量a作为参数传入到test函数中,如下:
a=10
def test(a):
a=a+1
print(a)
test(a) #11
输出就是11了。