对变量名的赋值和引用,是两种不同的情况:
- 赋值:创建一个变量或者修改。
- 引用:检索其值。
以上两者的差别,会导致我们在函数中:
- 赋值一个
- 全局变量:等于创建一个局部变量。
- 自由变量:等于创建一个局部变量。
- 引用:正常检索其值。
我们修改上例中的inner函数为如下形式:
- def inner(i1,i2='i2'):
- e = 'enclose'
- g = 'inner global'
- print(i1,i2,o1,o2,e,g,b)
在嵌套函数内,重新定义了g变量,其他语言一般理解这是重新赋值全局变量。但是我们看上条规则:在函数中,赋值一个全局变量时,等于创建一个局部变量。就是说此时的g已经是局部变量了——在程序最后的 print(g) 语句输出 global,而不是修改后的 inner global 也验证了以上规则。
完整代码如下:
- import builtins
- builtins.b = 'builtins'
- g = 'global'
- def outer(o1,o2='o2'):
- e = 'enclose'
- g = 'inner global'
- def inner(i1,i2='i2'):
- print(i1,i2,o1,o2,e,g,b)
- return inner
- fun = outer('o1')
- fun('i1')
- print(g)
输出结果如下:
- i1 i2 o1 o2 enclose inner global builtins
- global
不重新赋值,只是使用全局变量和自由变量,则没有问题。
自由变量也是类似的情况。
为了解决局部作用域中赋值全局变量和自由变量导致的变成局部变量问题,Python引入关键字 global 和 nonlocal 。
- def inner(i1,i2='i2'):
- global g
- nonlocal e
- g = 'inner global'
- e = 'inner enclose'
此时的赋值,则分别是对全局变量和自由变量的操作,而非新建局部变量。
完整代码如下:
- import builtins
- builtins.b = 'builtins'
- g = 'global'
- def outer(o1,o2='o2'):
- e = 'enclose'
- def inner(i1,i2='i2'):
- global g
- nonlocal e
- g = 'inner global'
- e = 'inner enclose'
- print(i1,i2,o1,o2,e,g,b)
- return inner
- fun = outer('o1')
- fun('i1')
- print(g)
输出结果如下:
- i1 i2 o1 o2 inner enclose inner global builtins
- inner global