2

我有这个代码:

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)

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

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

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

4

4 回答 4

6

不,在 python 2 中,如果不使用可变变量的技巧,你根本无法做到:

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)

通常,如果变量没有在本地分配,python 只会在周围范围内查找变量;一旦字节编译器看到一个直接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)
于 2012-06-15T20:02:58.280 回答
2

你可以做i一个函数属性

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

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

编辑:从 python 3 开始,您可以使用nonlocalla @MartijnPieters 的解决方案。

于 2012-06-15T20:03:19.557 回答
2

在 Python 中,如果您在函数内为变量赋值(即使使用复合赋值运算符,例如+=),除非globalornonlocal语句另有说明,否则该变量被视为局部变量。

于 2012-06-15T20:05:21.687 回答
1

当编译器看到该变量i在函数内部获得另一个值时,chapterReplacer它会将其视为本地变量,并且不应用“闭包魔法”。如果您删除 line i += 1,您的代码将运行。

于 2012-06-15T20:06:47.747 回答