2012-03-23 376 views
1

以下(荒诞而是说明性的)代码的工作通过突变在封闭函数定义的列表作为预期:对象可变性对Python的作用域有什么影响?

def outside1(): 
    l = list('abcd') 
    def inside(a): 
     print "Before - %i: %r" % (id(l), l) 
     l.append(a) 
     print "After - %i: %r\n" % (id(l), l) 
    return inside 

f = outside1() 
[f(c) for c in 'efgh'] 

该代码也可以表示,在一个封闭的范围限定的不可变的是封闭范围内的访问:

def outside2(): 
    t = tuple('abcd') 
    def inside(): 
     print "%i: %r" % (id(t), t) 
    return inside 

outside2()() 

但是这个失败local variable 't' referenced before assignment

def outside3(): 
    t = tuple('abcd') 
    def inside(a): 
     print "Before - %i: %r" % (id(t), t) 
     t = t + (a,) 
     print "After - %i: %r\n" % (id(t), t) 
    return inside 

f = outside3() 
[f(c) for c in 'efgh'] 

可有人è xplain这里发生了什么?我的第一个猜测是,我可以进行变异,但不能指定为封闭范围,但是如果outside2工作,我至少应该在打印声明之前工作

回答

6

Python在编译时静态检测名称范围:分配给函数内部的名称成为该函数的本地名称。太行

t = t + (a,) 

呈现t本地inside(),并tinside()任何查询将尝试查找的inside()一个局部变量。当上面的一行很好时,t还不存在,因此出现错误。

在Python 3.x中,您可以通过显式声明tnonlocal解决这一问题:

def outside3(): 
    t = tuple('abcd') 
    def inside(a): 
     nonlocal t 
     print("Before - %i: %r" % (id(t), t)) 
     t = t + (a,) 
     print("After - %i: %r\n" % (id(t), t)) 
    return inside 

这一切是完全无关的可变性。您使用列表的示例不会重新指定名称l,而使用元组的示例确实为重新指定t;这是重要的区别,而不是可变性。

+0

“Python在编译时静态检测名称的范围”谢谢,这是简短的答案; py3k的提示是一个不错的奖励。 – Finn 2012-03-23 14:17:53

3

可变性对范围没有影响。

问题是,分配给不在当前范围内的变量会创建该变量,而仅仅读取该变量则不会。

+0

Downvoter:你在这里有什么不同意? – Marcin 2012-03-23 14:24:53

+1

+1这是正确的答案 – newacct 2012-03-23 18:50:22

1

Marcin是对的。可变性对范围完全没有影响。

你需要了解的是,在第一个例子,而你是“突变列表中的”指向l,你只是读变量l,然后调用它的一些方法(.append())。这与您在阅读变量t的第二个示例中完全相同。

在这两种情况下,您都没有分配给外部范围的变量,只是简单地读取它。可变性仅仅意味着你可以改变变量所指向的东西,从而以这种方式共享变化。但从变量和范围来看,绝对没有区别。

在第三个示例中,您将分配给变量t。这是不同的。 Python 2.x无法通过global将全局变量分配给外部变量。 Python 3.x有nonlocal允许你这样做。需要注意的是可变性无关,用它做:如果你试图分配到(而不是仅仅发生变异的对象指向)在你的第一个实例变量l,你会碰到同样的问题:

def outside1(): 
    l = list('abcd') 
    def inside(a): 
     print "Before - %i: %r" % (id(l), l) 
     l = [1,2,3] 
     print "After - %i: %r\n" % (id(l), l) 
    return inside 
相关问题