变量起作用的代码范围称为变量的作用域,不同作用域内同名变量之间互不影响,就想不同文件夹的同名文件之间互不影响一样。一个变量在函数外部定义和在函数内部定义,其作用域是不同的,函数内部定义的变量一般为局部变量,在函数外部定义的变量为全局变量。
在函数内部定义的普通变量只在该函数内起作用,当函数运行结束后,在其内部定义的局部变量将被自动删除而不可访问。在函数内部定义的全局变量当函数结束以后仍然存在并且可以访问。
如果想要在函数内部修改一个定义在函数外的变量值,那么这个变量就不能是局部的,其作用域必须是全局的。可以在函数内部通过global关键字来声明或定义全局变量,这分两种情况:
(1)一个变量已在函数外定义,如果在函数内需要修改这个变量的值,并将这个赋值结果反映到函数之外,可以在函数内部用global明确声明要使用已定义的同名全局变量。
(2)在函数内部直接使用global关键字将一个变量声明为全局变量,如果在函数外没有定义该全局变量,在调用这个函数之后,会自动增加新的全局变量。
或者说,也可以这样理解:
<1>在函数内如果值引用某个变量的值而没有为其赋新值,该变量为(隐式的)全局变量;
<2>如果在函数内任意位置有为变量赋值的操作,该变量即被认为是(隐式的)局部变量,除非在函数内显式地用global进行声明。
下面的代码演示了局部变量和全局变量的用法。
1 >>> def demo(): 2 global x #声明或创建全局变量 3 x = 3 #修改全局变量的值 4 y = 4 #局部变量 5 print('全局变量:{} 局部变量:{}'.format(x,y)) 6 7 8 >>> x = 5 #在函数外部定义了全局变量 x 9 >>> demo() 10 全局变量:3 局部变量:4 11 >>> 12 >>> x 13 3 14 >>> y #尝试着在函数外部访问一下函数的局部变量 15 Traceback (most recent call last): 16 File "<pyshell#11>", line 1, in <module> 17 y #尝试着在函数外部访问一下函数的局部变量 18 NameError: name 'y' is not defined 19 >>> 20 >>> del x #删除在函数外部定义的全局变量 21 >>> 22 >>> x #尝试访问一下全局变量 x 23 Traceback (most recent call last): 24 File "<pyshell#15>", line 1, in <module> 25 x #尝试访问一下全局变量 x 26 NameError: name 'x' is not defined 27 >>> 28 >>> demo() #再调用一次函数,该函数会声明全局变量哦 29 全局变量:3 局部变量:4 30 >>> 31 >>> x #在函数内部创建了全局变量x 32 3 33 >>> 34 >>> y #局部变量在函数调用结束后自动删除 35 Traceback (most recent call last): 36 File "<pyshell#21>", line 1, in <module> 37 y 38 NameError: name 'y' is not defined 39 >>>
如果局部变量与全局具有相同的名字,那么改局部变量会在自己的作用域内隐藏同名的全局变量,例如下面的代码所演示。
1 >>> def demo(): 2 x = 3 #创建了局部变量,并自动隐藏了同名的全局变量 3 print(x) 4 5 6 >>> x = 5 #创建全局变量 7 >>> x 8 5 9 >>> 10 >>> demo() 11 3 12 >>> x #函数调用后,不影响全局变量 x 的值 13 5 14 >>> 15 16 # 个人理解: 17 # 局部变量的作用范围是函数体内,即使和全局变量同名了,在函数体内修改局部变量的值,也不会影响全局变量的值 18 19 # 在函数外修改全局变量的值,不会影响函数体内局部变量的值
最后,如果需要在同一个程序的不同模块之间共享全局变量,可以编写一个专门的模块来实现这一目的。例如,假设在模块A.py中有如下变量定义:
global_variable = 0
而在模块B.py中使用以下语句修改全局变量的值:
import A
A.global_variable = 1
在模块C.py中使用以下语句来访问全局变量的值:
import A
print(A.global_variable )
小提示:
(1)一般而言,局部变量的引用比全局变量速度快,应优先考虑使用;
(2)应尽量避免过多使用全局变量,因为全局变量会增加不同函数之间的隐式耦合度,降低代码可读性,并使得代码测试和纠错变得很困难。
拓展知识:局部变量的空间是在栈上分配的,而栈空间是由操作系统维护的,每当调用一个函数时,操作系统会为其分配一个栈帧,函数调用结束后立刻释放这个栈帧。因此,函数调用结束后,该函数内部所有的局部变量都不再存在。
拓展知识:除了局部变量和全局变量,Python还支持nonlocal关键字定义一种介于两者之间的变量。例如下面代码:
1 def scope_test(): 2 3 def do_local(): 4 spam = '我是局部变量' 5 6 def do_nonlocal(): 7 nonlocal spam #这时要求spam必须是已存在的变量 8 spam='我不是局部变量,也不是全局变量' 9 10 def do_global(): 11 global spam #如果全局作用域内没有spam,就自动创建一个 12 spam = '我是全局变量' 13 14 spam = '原来的值' 15 do_local() 16 print('局部变量赋值后:',spam) 17 do_nonlocal() 18 print('nonlocal变量赋值后:',spam) 19 do_global() 20 print('全局变量赋值后',spam) 21 22 23 scope_test() 24 print('全局变量:',spam) 25 26 #局部变量赋值后: 原来的值 27 #nonlocal变量赋值后: 我不是局部变量,也不是全局变量 28 #全局变量赋值后 我不是局部变量,也不是全局变量 29 #全局变量: 我是全局变量 30 31 #哈哈,感觉这个nonlocal就是用在嵌套函数中的,用于在子函数和父函数之间传递变量值的。而local是用于父函数和模块之间传递变量值的。这一点需要知道。