在Python 2中,如何向父作用域的变量写入?

78 投票
6 回答
26794 浏览
提问于 2025-04-16 10:56

我有一些代码如下:

def example():
    # other logic omitted

    stored_blocks = {}
    def replace_blocks(m):
        block = m.group(0)
        block_hash = sha1(block)
        stored_blocks[block_hash] = block
        return '{{{%s}}}' % block_hash

    num_converted = 0
    def convert_variables(m):
        name = m.group(1)
        num_converted += 1
        return '<%%= %s %%>' % name

    fixed = MATCH_DECLARE_NEW.sub('', template)
    fixed = MATCH_PYTHON_BLOCK.sub(replace_blocks, fixed)
    fixed = MATCH_FORMAT.sub(convert_variables, fixed)

    # more logic...

stored_blocks 里添加元素是没问题的,但我在第二个嵌套函数中却无法增加 num_converted 的值。我遇到了一个异常,提示 UnboundLocalError: local variable 'num_converted' referenced before assignment

我知道在 Python 3.x 中,我可以尝试使用 nonlocal num_converted,但在 2.x 中我该如何解决这个问题呢?我不想使用全局变量。

6 个回答

9

使用 global 这个关键词是没问题的。如果你写:

num_converted = 0
def convert_variables(m):
    global num_converted
    name = m.group(1)
    num_converted += 1
    return '<%%= %s %%>' % name

... num_converted 并不会变成一个“全局变量”(也就是说,它不会在其他意想不到的地方出现),它只是意味着可以在 convert_variables 这个函数里修改它。这正是你想要的效果。

换句话说,num_converted 本来就是一个全局变量。所有 global num_converted 这段代码的作用就是告诉 Python:“在这个函数里,不要创建一个新的本地 num_converted 变量,而是使用已经存在的全局变量。”

29

(请看下面的编辑过的回答)

你可以使用类似这样的代码:

def convert_variables(m):
    name = m.group(1)
    convert_variables.num_converted += 1
    return '<%%= %s %%>' % name

convert_variables.num_converted = 0

这样一来,num_converted 就像C语言中的“静态”变量,属于convert_variable这个方法。


(编辑过的)

def convert_variables(m):
    name = m.group(1)
    convert_variables.num_converted = convert_variables.__dict__.get("num_converted", 0) + 1
    return '<%%= %s %%>' % name

这样,你就不需要在主程序里初始化计数器了。

88

问题: 这是因为Python的作用域规则有点奇怪。当你使用+=这个赋值操作符时,它会把目标变量num_converted标记为当前函数的局部变量。在Python 2.x中,没有简单的方法可以只访问外层作用域的一个层级。只有global这个关键词可以把变量引用提升到当前作用域之外,但它会直接把你带到最外层。

解决办法:num_converted变成一个只有一个元素的数组。

num_converted = [0]
def convert_variables(m):
    name = m.group(1)
    num_converted[0] += 1
    return '<%%= %s %%>' % name

撰写回答