再谈python的变量作用域

Posted 黑猫-警长

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了再谈python的变量作用域相关的知识,希望对你有一定的参考价值。

一直觉得python的作用域不是什么难点,但是前几天在另一个博客平台上看到一段代码,又把我弄糊涂了,于是看书,把作用域又看了一遍,重新总结一下知识要点和坑,做个笔记
所有代码基于python2.7.10
基本概念和知识点不多说,直接上代码:

bar = 200
def foo():
    print bar
foo()  # 200

这段代码是没有错的,再看看下面一段:

bar = 200
def foo():
    bar = 100
    print bar
foo()  # 100

foo()中声明了局部变量bar,所以最后打印的是100,这也是毋庸置疑的
但是再看看下面的代码,也是让我感到迷惑的代码:

bar = 200
def foo():
    print bar
    bar = 100 
foo()  # 出现错误

出现异常UnboundLocalError: local variable ‘bar’ referenced before assignment
这让我有点迷惑,这和我想的有点不一样,于是在书上找到了这样的解释:

当使用全局变量同名的局部变量的时候要小心.如果在赋予局部变量值之前,你在函数中(为了访问这个全局变量)使用了这样的名字,你将会得到一个异常(NAMEERROR或者Unbound-LocalError),抛出哪个异常取决与python版本.

这样的代码确实也是很让人迷惑,全局变量和局部变量全搅乱了,python直接抛出异常的行为我觉得是很好的:直接就不让你写这样的代码.
但是如果真有这种情况呢,就要使用global关键字了.声明为全局变量,然后随便你怎么折腾:

bar = 200
def foo():
    global bar
    print bar
    bar = 100
print bar  # 200
foo()  # 200
print bar  # 100

这就很清楚了.如果global不是位于函数的顶部,而是使用或赋值变量之后,会有警告:

bar = 200
def foo():
    print bar
    global bar
    bar = 100
foo()  # 200  

会出现警告:

SyntaxWarning: name ‘bar’ is used prior to global declaration
global bar

这样也会有警告:

bar = 200
def foo():
    print bar
    bar = 100
    global bar
foo()  # 200 
print bar  # 100

警告和之前不一样:

SyntaxWarning: name ‘bar’ is assigned to before global declaration
global bar

最后print bar 的结果是100,也就是说全局变量bar被改成了100.
在foo里虽然是先有bar = 100然后才有global bar但bar仍然被当作全局变量赋值为100.

以上是关于再谈python的变量作用域的主要内容,如果未能解决你的问题,请参考以下文章

再谈闭包

再谈类和对象

再谈JavaScript中的闭包

再谈js的作用域

再谈闭包

Python变量作用域