16_Python变量作用域_Python编程之路
之前跟大家已经讲了有关函数的一部分知识,但是忘了讲一个很重要的点,就是变量的作用域,这块知识不只是适用于函数,它试用域所有的Python程序
在正式写程序之前,必须要清楚这一块,否则就很容易犯错误
首先理清一个概念,什么是变量
变量可以我们可以将它看为指向值的名称,就像我们之前讲的字典一样的,只是这个字典你是看不到,当然这是很通俗的解释,但也离真相不远了
在Python中有一个vars的内置函数,他可以返回这个看不见的“字典”
比如以下代码
In [1]: a = 100 In [2]: distrue = vars() In [3]: distrue["a"] Out[3]: 100 In [4]: distrue["a"] += 100 In [5]: a Out[5]: 200
是不是非常神奇,把变量变成了一个键值对应的字典,而且还可以通过索引更改值
在这里要注意一点,根据官方文档,是不应该修改vars返回的字典的,这样会使得结果不确定
我们把这种看不见的字典叫做命名空间或者是作用域
作用域
我们现在给出以下代码
In [7]: a = 100 In [8]: def func_one(): ...: a = 200 ...: In [9]: func_one() In [10]: a Out[10]: 100
一开始,我们定义了一个变量,将100赋值给了a,然后我们后面定义了一个方法,将200赋值给a
之后,我们调用了这个方法,但是,最后a的值并没有改变,这个就牵涉到有关变量作用域的问题了,我们慢慢解释
首先我们调用func_one时是创建了一个新的命名空间,以供func_one中的代码块使用,而赋值语句a = 200是在这个函数内部的作用域执行的,也就是一个局部命名空间,他是不会影响外部作用域(或者是全局)的变量,
在函数内部使用的变量我们把它成称为局部变量,在函数外的就称作全局变量
参数是类似于局部变量的,所以他的命名即使与全局变量相同也是没有关系的
比如下面的一个输出函数
In [12]: def output(x): ...: print(x) ...: In [13]: x = 10 In [14]: y = 20 In [15]: output(y) 20 In [16]: output(x) 10
函数访问全局变量
只是读取值得话,非常简单
比如以下代码
In [18]: def linkval(words): ...: print(words + external) ...: In [19]: external = " susmote" In [20]: linkval("hello") hello susmote
但是,在这提醒以下,这种方法还是慎用,很容易造成bug
这个时候,我们又遇到了一个新的问题,如果局部变量和全局变量相同的话,就会出现遮盖的问题
稍微改一下上面的代码,问题就出现了
In [21]: def linkval(words): ...: external = " jack ma" ...: print(words + external) ...: In [22]: external = " susmote" In [23]: linkval("hello") hello jack ma
也就是说,全局变量被局部变量给遮住了
如果实在有需要的话,可以使用globals函数来访问全局变量,他会返回一个包含全局变量的字典,也就是说可以通过字典的键索引获取值
(相对的locals返回一个包含局部变量的值)
还是上面的代码,我们稍稍做一点改变,结果就会截然不同
In [24]: def linkval(words): ...: external = " jack ma" ...: print(words + globals()['external']) ...: In [25]: external = " susmote" In [26]: linkval("hello") hello susmote
函数中定义全局变量
一般我们在函数中定义变量,它默认是局部变量,但是我们可以直接声明定义的变量为全局变量,这时我们就必须用到global这个关键词了
In [32]: a = 100 In [33]: def func_one(): ...: global a ...: a += 100 ...: In [34]: func_one() In [35]: a Out[35]: 200 In [36]: func_one() In [37]: a Out[37]: 300
作用域的嵌套
之前有一个概念没有讲到,就是函数的定义是可以嵌套的,类似于一个函数中,还可以定义函数,类似于以下代码
In [45]: def func_one(): ...: def func_two(): ...: print("内层函数") ...: print("外层函数") ...: func_two() ...: In [46]: func_one() 外层函数 内层函数
嵌套函数实际作用并不大,但他的一个突出的功能还是不错的,使用一个函数来创建另一个函数
例如以下代码
In [48]: def adder(factor): ...: def addByFactor(number): ...: return number + factor ...: return addByFactor ...: ...: In [49]: adder(10)(10) Out[49]: 20 In [50]: adder(100)(100) Out[50]: 200
一个函数位于另一个函数中,而且外面的函数返回的是里面的函数,没有调用这个函数
其中,最重要的一点是,返回的函数能够访问其定义所在的作用域,也就是说,他返回时,还带着他自己所在的环境(相关的局部变量)
放到实际中来说就是可以在内部函数中访问这个来自外部作用域的局部变量
我们把这种函数称之为 闭包
如果要给外部作用域的变量赋值,可以用nonlocal关键词,这有点类似于global
关于作用域我要讲的就是这些,通过简单的练习,就能很快理解