在函数内部作用域生效。这个算非正常程序员的写法了,import语句在函数import_sys中将名字sys和对应模块绑定,那sys这个名字还是定义在局部作用域,跟上面的例子没有任务区别。要时刻切记Python的名字,对象,这个其他编程语言不一样。
只引用上层作用域中的值时:
在局部作用域中可以引用全局作用域中的命名空间。
注:可不要认为i=0这行必须卸载def test()前面,事实上只需要在test()函数调用前写i=0即可,因为函数的命名空间是在函数被调用时创建的。
继续上面的例子,若是对值进行修改:
报错:UnboundLocalError: local variable 'i' referenced before assignment
Python对局部作用域情有独钟,解释器执行到print(i),i在局部作用域没有。解释器尝试继续执行后面定义了名字i,解释器就认为代码在定义之前就是用了名字,所以抛出了这个异常。如果解释器解释完整个函数都没有找到名字i,那就会沿着搜索链LEGB往上找了,最后找不到抛出NameError异常。
是不是觉得另有所悟,对上面的代码稍作修改,能否推测出结果:
我想你应该猜到了结果,这个和上面的例子基本是一样的。再改一下:
输出结果:
[2, 2]
猜到了吗?是不是有些懵逼。list作为一个可变对象,l[0] = 2并不是对名字l的重绑定,而是对l的第一个元素的重绑定,所以没有新的名字被定义。因此在函数中成功更新了全局作用于中l所引用对象的值。
请对比下面几种示例代码:
第一种:
第二种:
第三种:
先别看答案,想想输出结果!
第一种输出结果:
1
1
第二种输出结果:
1
1
第三种输出结果:
2
1
为什么会这样呢?上面说到过,函数的作用域是静态的,由函数声明的位置决定,在哪里声明,就决定了它的上层作用域是谁,这与调用函数的位置无关。无论在哪里调用,它都会去函数本身的作用域中的命名空间找,找不到在去上一层的命名空间找,切记未必是在调用该函数的作用域的命名空间找。对于第三种情况,是最让我费解的地方,func = f1()执行完之后,f1的命名空间被销毁,按理说就找不到i=2了,但是输出结果确实是2,所以我只能用LEGB搜索法则解释。(如果你知道为什么,请给我留言,感激不尽……)
代码运行后报错:NameError: name 'a' is not defined。上文中说过,Python类成员变量与成员函数都有自己的作用域,且各作用域平级。(用作用域的生命周期来解释也行,但是真心觉得不对劲)。
Python的作用域与命名空间有的时候真的让人很费解,我本以为与Java等语言类似的,没想多还是挺有区别的。有些情况我到现在也没想通,例如作用域与命名空间的生命周期,用生命周期来解释上面的一些例子,总觉得不对劲。