Skip to main content
 首页 » 编程设计

python之对象可变性对 python 中的范围有什么影响

2025年05月04日9luoye11

以下(荒谬但说明性的)代码通过改变封闭函数中定义的列表按预期工作:

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;这是重要的区别,而不是可变性。