阅读本文大概需要:4 分钟
经常会有人一言不合的扔过代码来问我这是怎么回事,每次我都瞪着我的 24k 氪金眼扫描,时间长了我发现有一种类型的问题出错的频率之高令人发指,每次说这个问题说的我嘴巴都干了,昨天情人节的时候竟然还有位老哥扔过这么个问题,看样子是哪个面试题?我是有女朋友的好嘛,我女朋友不撒娇,不做作,不粘人,不生气,不存在。。
还是给人解决一下吧,为了以后有人再问我同类问题的时候不再把嘴巴说干,我决定写下这篇文章,方便我以后优雅的把文章扔过去。。
先来看一个简单的例子,简单却很经典:
>>> a = 1
>>> def func1():
... return a
...
>>> def func2():
... a += 1
... return a
...
看,一个简单的例子,那么问题来了:你知道分别调用这两个函数以后,出现的结果是多少吗?自己想思考一下,然后请继续向下看:
>>> func1()
1
>>> func2()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in func2
UnboundLocalError: local variable 'a' referenced before assignment
咦?为什么 func2() 会报错呢?
其实当我们在「作用域」中对变量进行赋值的时候,变量就会变成该作用域的「局部变量」,所以在 func2() 函数中,a 其实是变成了这个函数中的局部变量,变成局部变量以后这还不完,a += 1,看着写的没什么问题,其实你仔细看看,在 func2() 的函数作用域里 a 并没有被初始化,所以才会报错。
那么如何才能让它不报错且出现我们想要的结果呢?很简单,就是在 func2() 中修改外部作用域变量 a,可以使用 global 完美解决,就像下面这样:
>>> def func2():
... global a
... a += 1
... return a
...
我们来看一下它的输出结果:
>>> func2()
2
可能看到这很多人只知道该怎么用,还是有些似是而非,其实很多源于对概念的不理解,比如我在上面说的「局部变量」,「作用域」等等很多人就有点晕了。
「局部变量」其实是只在函数内部起作用的变量,那么有了「局部」就得有「全部」啊,但是后者听起来怪怪的,所以我们就把「全部」改成了「全局」。我们在上面代码中的 global a,其实就是在声明 a 是「全局变量」。
很多时候初学者乍一看觉得全局变量好强,可以管着函数的内外,但是哪有那么强的东西,我们还是要注意全局变量还是要谨慎去用,毕竟内外有别,不要带来混乱。
至于「作用域」的话,用比较直白的方式来说,就是程序中变量和对象存在关联的那段程序,比如在上面的 a = 1 和 a += 1 就是在两个不同的作用域中。
知道了「局部变量」、「全局变量」和「作用域」以后,就可以去理解「命名空间」。这些东西其实我在很久以前的文章中都详细的写过,后来关注的朋友们可能不太清楚,我把它放在下面,供大家详细学习。
以上。