Discuss / Python / 关于闭包,还是理解得不透彻

关于闭包,还是理解得不透彻

Topic source

Zack_Chang

#1 Created at ... [Delete] [Delete and Lock User]

第一次尝试:

def createCounter():
    i = 0
    def counter():
        i += 1
        return i
    return counter

结果出现全局变量错误

UnboundLocalError: local variable 'i' referenced before assignment

第二次尝试, 声明变量i并非counter()得局部变量:

def createCounter():
    i = 0
    def counter():
        nonlocal i
        i += 1
        return i
    return counter

或者根据大家的答案,将变量i改为列表:

def createCounter():
    i = [0]
    def counter():
        i[0] += 1
        return i[0]
    return counter

为什么在不声明的情况下,counter()将变量i视为局部变量,而不会将列表i[]视为局部变量,而是直接引用上一层函数的列表i,不是很明白

上面的评论说[0]算是一个地址,不管把什么样的结果存到里面都不会改变这个地址,但是i就是单纯的一个变量,随着你赋给它的值在变化。我感觉说的挺有道理。。。

i 是 不可变对象。

i = [0] 是数组,是可变对象,把i[0]重新赋值只是把i数组的[0]元素替换了。

def counter():
        i += 1

这样做是不对的,因为 i += 1 相当于 i = i + 1 也就是说在内部函数counter中,重新声明了一个 i 这样的话,i 就被引进到了内部的命名空间,不再是外面那个i , 不能从外部函数获取值了,这时候 i 是没有值的,计算 i + 1 会出错。好懂一点的办法是,声明一个新变量比如 j = i + 1 然后把 j 返回出去。如果只想用 i 那就得 像你的第二份代码那样

nonlocal i

把内部函数中的 i 声明到外部函数的命名空间里,使之视为同一个 i 。

李武侯

#4 Created at ... [Delete] [Delete and Lock User]

看了蛮吉老哥的回复,我恍然大悟

-永无涯-

#5 Created at ... [Delete] [Delete and Lock User]

这个问题纠结了半天,看到这个讨论终于明白了。发现这是Python自动定义变量产生的问题,i=i+1本来只是一个赋值指令,但Python就会当成重新定义i,所以要使用i就要用nonlocal i。感谢~


  • 1

Reply