需要帮助理解Python闭包

Bwm*_*mat 2 python closures

我有这个代码:

import re

def doReplace(toReplace):
    i = 1
    def chapterReplacer(_):
        result = 'Chapter %i' % i
        i += 1
        return result

    return re.sub('Chapter [a-zA-Z]+', chapterReplacer, test)

test = 'Chapter one Chapter Two Chapter three'
print doReplace(test)
Run Code Online (Sandbox Code Playgroud)

当我运行它时,我收到以下错误:

Traceback (most recent call last):
  File "C:/Python26/replace.py", line 13, in <module>
    print doReplace(test)
  File "C:/Python26/replace.py", line 10, in doReplace
    return re.sub('Chapter [a-zA-Z]+', chapterReplacer, test)
  File "C:\Python26\lib\re.py", line 151, in sub
    return _compile(pattern, 0).sub(repl, string, count)
  File "C:/Python26/replace.py", line 6, in chapterReplacer
    result = 'Chapter %i' % i
UnboundLocalError: local variable 'i' referenced before assignment
Run Code Online (Sandbox Code Playgroud)

我的印象是chapterReplacer会捕获局部变量i,但这似乎没有发生?

Mar*_*ers 6

不,并且在python 2中,你根本不能使用带有mutable的技巧:

def doReplace(toReplace):
    i = [1]
    def chapterReplacer(_):
        result = 'Chapter %i' % i[0]
        i[0] += 1
        return result

    return re.sub('Chapter [a-zA-Z]+', chapterReplacer, test)
Run Code Online (Sandbox Code Playgroud)

通常情况下,如果变量未被分配到本地,则python将只查看变量的周围范围; 一旦bytecompiler看到直接赋值(i = something)并且没有global i语句来说服它,否则变量被认为是本地的.

但是在上面的代码中我们从未ichapterReplacer函数中赋值.是的,我们确实会改变,i[0]但存储在其中的值(i列表)不会改变.

在python 3中,只需使用该nonlocal语句让python查看变量的闭包:

def doReplace(toReplace):
    i = 1
    def chapterReplacer(_):
        nonlocal i
        result = 'Chapter %i' % i
        i += 1
        return result

    return re.sub('Chapter [a-zA-Z]+', chapterReplacer, test)
Run Code Online (Sandbox Code Playgroud)

  • 因为你不是在重新'i`; 只有`i`的成员.变量本身恰好是可变的,但由于它的直接值(列表)不会改变,python将查看周围的范围. (3认同)