您的位置:首页 > 编程语言 > Python开发

python变量作用域

2011-09-14 11:04 501 查看
昨天学习了python的静态嵌套域,但是网上差了很多资料看了很多博客,也没有弄清除,最后还是得看PEP227.在PEP227中原文是这样说的:
The Python 2.0 definition specifies exactly three namespaces to check for each name --
the local namespace, the global namespace, and the builtin namespace.  According to this definition,
if a function A is defined within a function B, the names bound in Bare not visible in A.
The proposal changes the rules so that names bound in B are visible in A (unless A contains a name binding that hides the binding in B).
其实也就是说当函数A定义在函数B中时,即嵌套定义时,函数B中的变量在函数A中是不可见的,
此时python称函数A中的B的变量为自由变量,函数A为闭包,而在python2.1以后B中的变量在A中是可见的了,我写了个程序试了下,发现确实是这样:
#!/user/bin/env python
def foo():
m=3
def bar():
print m
bar()
print m
foo()
结果bar()中的print 语句一样可以打出m的值,但是如果在bar()中声明了一个局部变量m,这是bar()中的m就会屏蔽foo()中的m,这一点与C/C++是一样的。
我又试着写了这样一个程序:
#!/user/bin/env python
def foo():
m=3
def bar():
z=4
print m
bar()
print z
foo()
这个程序实在bar()中申明了一个变量z,然后在foo中打印z,结果发现此时python编译器会报错
此外,对于静态嵌套域还有其他的规则,在这里引用一下双宇的博文:
如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure).闭包在函数式编程中是一个重要的概念。语法上看比较简单,但是用处却是相当广泛的。
在Python 2.1版本以前,只有全局域和局部作用域,而在2.1以后的版本中我们可以使用静态嵌套域,如像下面这样的嵌套函数中,在以前,内部函数是不能访问外部函数作用域中的变量的。
def foo():
m = 3
def bar():
n = 4
print m + n
print m
bar()

在现在的版本中可以完美运行,而bar()中的 m
就是一个既不属于全局域又不属于局部域的闭包变量,它存活在一个函数的名称空间和作用域---嵌套作用域。而在闭包中对嵌套作用域中的访问规则与上面讨论
的Global是一样的。即在对闭包变量 m 的重新声明之前引用 m 都会引发异常
def foo():
m = 3
def bar():
print m #UnboundLocalError
m=4
print m
bar()
UnboundLocalError: local variable 'm' referenced before assignment

什么会这样呢?其实是因为m的类型有关,我们知道Pyhton中的基本数据类型分为可变和不可变,对于不可变类型的赋值,其实是重新定义一个新的变量对
象,并深拷贝原对象到新对象,参考str类型说明。如果将上面的 m 声明成可变类型list,那就不会产生这个异常了。
def foo():
m = [3]
def bar():
print m[0]
m[0]=4
print m[0]
bar()
关于可变类型与不可变类型的说明,这里就不展开说了,大家可以看API Document下面举一个闭包的实际例子:
def hellocounter (name):
count=[0]
def counter():
count[0]+=1
print 'Hello,',name,',',str(count[0])+' access!'
return counterhello = hellocounter('ysisl')
hello()
hello()
hello()Console output:
Hello, ysisl , 1 access!
Hello, ysisl , 2 access!
Hello, ysisl , 3 access!

个例子中,hellocounter(name)返回了一个内部函数counter的引用,就像C++中指向函数的指针一样,我们把这个引用用一个变量
hello来保存,那么这个变量就代表了这个counter函数,为什么对hello()的反复调用能保持闭包变量count的自增,而不是释放后再重新
分配?因为count不是counter的局部变量,它是一个在hellocounter()范围内游离于counter之外的变量,只有当
hellocounter(name)被调用时,count才被重新分配新的内存地址。双宇原文地址:http://www.cnblogs.com/ysisl/archive/2009/08/17/1548075.html

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: