在Python 2中,如何向父作用域的变量写入?
我有一些代码如下:
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 个回答
使用 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
变量,而是使用已经存在的全局变量。”
(请看下面的编辑过的回答)
你可以使用类似这样的代码:
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
这样,你就不需要在主程序里初始化计数器了。
问题: 这是因为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