Python学习笔记:全局变量(global关键字)、局部变量的用法
1、全局变量
定义在函数体外,模块内的变量称为全局变量。
- 全局变量在所有函数体内都可以进行访问
- 全局变量在函数体内不能直接修改绑定关系
全局变量声明在全局命名空间中,作用域是当前文件中的所有位置。
a = 100
def test():
a = 50
print(a)
test()
print(a)
输出结果
50
100
1)全局变量的用法
① python的全局变量的作用域为特定模块之内
② 在函数内,如不加global关键字,则该变量为局部变量,如该变量未声明,如对变量进行修改,会出问题。
a = 2
def f(a):
print(a)
def main():
a += 1
if __name__ == '__main__':
main()
该方法会提示a为本地变量;
要想使用,必须在函数内提供global关键字,才会让global变量起作用。
a = 2
def f(a):
print(a)
def main():
global a
a += 1
if __name__ == '__main__':
main()
2)全局变量的实质
python在程序运行时,提供了一个__globals__字典,__globals__字典属于模块,并把全局变量放入字典里。
这种方式,决定了python的全局变量不属于进程而属于模块。
3)全局变量的修改
① 不可变类型全局变量
如:字符串
如果要修改的全局变量是不可变类型,直接使用global 引入并修改。
name = "tom"
def test():
global name
name = "jerry"
test()
print(name)
# jerry
② 可变类型全局变量
如:列表
修改可变类型内部的数据,直接修改即可。
给可变类型全局变量重新赋值,需要使用 global关键字引入。
例1:
lst = [1]
def test():
# 修改可变类型内部的数据,直接修改即可
lst.append(2)
test()
print(lst)
# [1, 2]
=======================
lst = [1]
def test():
# 给可变类型全局变量重新赋值,需要使用 global关键字引入
global lst
lst = [1,2,3]
test()
print(lst)
# [1, 2, 3]
例2:
>>> a = 1
>>> def f():
... a += 1
... print a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in f
UnboundLocalError: local variable 'a' referenced before assignment
>>> li = [1,]
>>> def f2():
... li.append(1)
... print li
[1, 1]
[1, 1]
在函数中不使用global声明全局变量时不能修改全局变量的本质是不能修改全局变量的指向,即不能将全局变量指向新的数据。
对于不可变类型的全局变量来说,因其指向的数据不能修改,所以不使用global时无法修改全局变量。
关于Python的数据类型分类如下图所示:
Python数据类型这一块的学习点是比较多而细的,基本上无论什么教程,都是会把这个数据类型拿出来讲透,因为这部分不吃透,后面的学习会寸步难行。
上面这几个核心数据类型的学习难度倒不是很大,零基础初学者也不用太过于担心。
下面的链接说的详细明白,可以学习一下↓↓
4)小结
- 在函数外边定义的变量叫做全局变量
- 全局变量能够在所有的函数中进行访问
- 如果在函数中修改全局变量,那么就需要使用global进行声明,否则出错
- 如果全局变量的名字和局部变量的名字相同,那么使用的是局部变量的,小技巧强龙不压地头蛇
2、局部变量
定义在函数体内部的变量称为局部变量;
当你在一个函数的定义中声明变量时,它们不会以任何方式与身处函数之外但具有相同名称的变量产生关系,也就是说,这些变量名只存在于函数这一局部(Local)。
函数的形参也是局部变量;
局部变量的作用范围只在声明该局部变量的函数体内
声明在函数内部的变量,只能在当前函数内部访问,函数执行完成后(堆内存执行完成后函数就回收),局部变量就随着函数被回收了!
如果一个数据,在函数中临时使用,使用完之后就没有作用的数据,就可以声明为局部变量在当前函数内部使用。
案例:
def func(x):
print('x is', x)
x = 2
print('Changed local x to', x)
func(x)
print('x is still', x)
输出:
x is 50
Changed local x to 2
x is still 50
当第一次打印出存在于函数块的第一行的名为 x 的值时,Python 使用的是在函数声明之上的主代码块中声明的这一参数的值。
接着我们将值 2 赋值给 x,x 是我们这一函数的局部变量。因此,当我们改变函数中 x 的值的时候,主代码块中的 x 则不会受到影响。
随着最后一句 print 语句,我们展示出主代码块中定义的 x 的值,由此确认它实际上不受先前调用的函数中的python局部变量的影响。
小结:
- 局部变量,就是在函数内部定义的变量
- 不同的函数,可以定义相同的名字的局部变量,但是各用个的不会产生影响
- 局部变量的作用,为了临时保存数据需要在函数中定义变量来进行存储,这就是它的作用
看到这里应该对全局变量和局部变量有个大致的印象了,新手还有疑问也没有关系,都是这样过来的,建议学习的时候多问多动手,学编程主要还是以实际操作为主。
项目实操动手有困难的,推荐一个前辈的直播课分享,他会定时在群里直播免费分享Python学习干货以及项目实操演练,非常实用。
听课传送门:
https://www. zhihu.com/question/4516 04793/answer/1850553245
3、global 关键字的用法
1)作用
声明一个或多个变量,这些变量的作用域为模块级的作用域的变量,即全局变量。
将赋值变量映射到模块文件内部的作用域
a = 10
def test():
global a
a = 5
print(a)
test()
print(a)
输出结果
5
5
2)说明
① 全局变量如果要在函数内部被赋值,则必须经过全局声明,否则会被认为是局部变量
② 不能先声明局部变量,再用global声明为全局变量
③ global变量列表里的变量名不能出现在次作用域内的形参列表
3)引例分析
有时候在写函数的时候,由于传参实在太多,于是将某个数组定义为全局变量,在函数中直接使用,结果在使用过程中出现报错,原因是在另一个调用函数中,该全局变量的类型被修改了
先来看一个例子分析,代码如下:
#error case
param = 10
def test():
if (param == 10):
print("equal 10")
else:
print("not equal 10")
def main():
global param
param = "hello world"
test()
if __name__ == "__main__":
main()
这个程序的输出结果是“not equal 10”,并不是预期中的“equal 10”。
来看一下原因
在 main() 函数中,param 先被当做全局引用,并修改了他的类型,从 int 型变成了 str 型,所以在后面调用 test() 函数的时候,判定 param==10 结果为false。
即使把 test() 函数放到以下位置,也不会改变输出结果。
#error case
param = 10
def test():
if (param == 10):
print("equal 10")
else:
print("not equal 10")
def main():
global param
param = "hello world"
if __name__ == "__main__":
main()
test()
解决办法:应该只能通过传参,并且对于全局变量不要随意修改。
反正 PYTHON 在函数外定义的变量均当做全局变量来处理,也不需要画蛇添足加上 global 关键字,只有当确认需要对 global 变量做出修改的时候,再使用 global 关键字!
再来看看另外一个例子
param = 10
def main():
print("param_value:%d\t param_id:%d" %(param, id(param)))
if __name__ == "__main__":
main()
PYTHON 变量默认是全局变量,在不申明 global param 的情况下,程序可以正确输出:
“param_value:10 param_id:140704526292288”
但是当 param 被 global 申明,结果好像不一样
#error case
param = 10
def main():
print("param_value:%d\t param_id:%d" %(param, id(param)))
global param
param = 6
print("param_value:%d\t param_id:%d" %(param, id(param)))
if __name__ == "__main__":
main()
依然是申明了变量,但是在 global 之前获取了 param 的值和 id。
这种情况下,程序会报 syntax error;
理由: “name 'param' is used prior to global declaration”,即变量在定义之前就被使用。而只要变量在这个函数块内被申明,他的作用域就是整个函数,如果在申明之前被引用,那就会报错。
下面示例比较清楚的展示了 global 的用法:
param = 10
def test():
print("param_value:%d\t param_id:%d" %(param, id(param)))
if (param == 10):
print("equal 10")
else:
print("not equal 10")
def main():
global param
print("param_value:%d\t param_id:%d" %(param, id(param)))
param = 6
print("param_value:%d\t param_id:%d" %(param, id(param)))
test()
if __name__ == "__main__":
print("param_value:%d\t param_id:%d" %(param, id(param)))
main()
输出结果
param_value:10 param_id:140704526292288
param_value:10 param_id:140704526292288
param_value:6 param_id:140704526292160
param_value:6 param_id:140704526292160
not equal 10
4、使用函数查询全局变量和局部变量
如果一个 python文件中会出现全局变量和局部变量,能否通过固定的语法查询到这些出现的变量,直观的看到一个文件中都有哪些全局变量?一个函数中都有哪些局部变量呢?
- globals() 访问一个文件中的全局变量
- locals() 访问代码所在位置命名空间中的变量
放在函数中,访问的就是当前函数的局部变量;
放在函数外,访问的就是和 globals() 一样的全局变量;
5、变量的查询顺序
想一想下面的代码运行出现什么结果?为什么?
name = "tom"
def test():
print(name)
name = "jerry"
test()
1)表现
会出现 UnboundLocalError 错误,使用了一个未赋值的局部变量
2)规则
变量使用时,查询顺序就近原则【找变量离自己声明最近的一份命名空间】
3)python 中有一个固定的查询顺序,LEGB原则【就近原则】
如下:
L -> Local 本地:局部 函数内部声明的变量
E -> Enclosing:嵌套:函数内部
G -> Global:全局:python文件的内部
B -> Builtins:python内建
4)底层
函数内部使用一个变量时,底层代码将变量的声明提升到函数的头部,但是赋值的过程还在原来的位置,此时如果在赋值之前使用变量,就会出现变量和值没有绑定的情况,于是就出现了 UnboundLocalError。
5)引用顺序
Python引用变量的顺序:当前作用域局部变量->外层作用域变量->当前模块中的全局变量->Python内置变量。
6、补充:作用域
作用域也叫命名空间,是访问时查找变量的范围空间。
python3有四个作用域
当访问一个变量的时候,变量查找顺序是先查找本地变量,然后是包裹此函数外部的函数内的变量,之后是全局变量,最后是內建作用域内的变量。
在默认情况下,变量名赋值会在当前作用域内创建变量和修改变量。
v = 100 # 全局作用域
def fun1():
v = 200 # 外部嵌套函数作用域
print('fun1.v=', v)
def fun2():
v = 300 # 局部作用域
print('fun2.v=', v)
print(max) # max函数都没有创建,在内建函数作用域中,只读,不能改变
# 可以在其余三个作用域重新创建。
fun2()