以下(荒谬但说明性的)代码通过改变封闭函数中定义的列表按预期工作:
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']
此代码还表明在封闭范围内定义的不可变对象(immutable对象)在封闭范围内是可访问的:
def outside2():
t = tuple('abcd')
def inside():
print "%i: %r" % (id(t), t)
return inside
outside2()()
然而,由于 局部变量 't' 在赋值前被引用 而失败了:
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']
有人能解释一下这是怎么回事吗?我的第一个猜测是我可以改变但不能分配给封闭范围,但我至少希望 before 打印语句能够工作,因为 outside2 工作。
请您参考如下方法:
Python 在编译时静态检测名称的范围:分配给函数内部的名称成为该函数的局部名称。所以行
t = t + (a,)
将 t 渲染到 inside() 本地,并在 inside() 中查找 t将尝试查找 inside() 的局部变量。当上面一行被执行时,t 还不存在,因此错误。
在 Python 3.x 中,您可以通过将 t 显式声明为 nonlocal 来解决该问题:
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;这是重要的区别,而不是可变性。
