我对局部变量和python(2.7)有点问题。
我有一些代码:
def foo(a):
def bar():
print a
return bar()
>>>foo(5)
5
嗯,它正在工作,但是如果想修改一个,就像这样:
def foo(a):
def bar():
a -= 1
return bar()
>>>foo(5)
UnboundLocalError: local variable 'a' referenced before assignment
所以我必须将'a'影响到另一个变量。
但我不明白这种情况。 是因为当有一个赋值时,python会查找locals()变量并找不到它吗?
感谢。
答案 0 :(得分:8)
你在Python中发现了一些曾经存在问题的东西!简短的回答是,您不能在Python 2.x中执行此操作(尽管您可以simulate),但您可以使用nonlocal
关键字在3.x中执行此操作。
请参阅PEP 3104:
在2.1版之前,Python对范围的处理类似于 标准C:在一个文件中只有两个范围的级别,全局 和当地的。在C中,这是事实的自然结果 函数定义不能嵌套。但在Python中,虽然功能 通常在顶层定义,函数定义可以 执行任何地方这给了Python嵌套的句法外观 没有语义的范围,并产生了不一致 令一些程序员感到惊讶 - 例如,递归函数 在顶层工作时,在内部移动时将停止工作 另一个函数,因为递归函数自己的名字不会 在身体的范围内可以看得更久。这违反了直觉 放置在不同的函数时,函数应该表现一致 上下文。这是一个例子:
def enclosing_function(): def factorial(n): if n < 2: return 1 return n * factorial(n - 1) # fails with NameError print factorial(5)
Python 2.1通过使其可见而更接近静态嵌套作用域 绑定在所有封闭范围内的名称(参见PEP 227)。这种变化使 上面的代码示例按预期工作。但是,因为任何 对名称的赋值隐式声明该名称是本地的,它是 不可能在外部范围内重新绑定名称(全局除外) 声明强制名称为全局名称。因此,以下代码, 旨在显示可以递增和递减的数字 通过单击按钮,不能像熟悉词汇的人那样工作 范围可能会有所期待:
def make_scoreboard(frame, score=0): label = Label(frame) label.pack() for i in [-10, -1, 1, 10]: def increment(step=i): score = score + step # fails with UnboundLocalError label['text'] = score button = Button(frame, text='%+d' % i, command=increment) button.pack() return label
Python语法没有提供表明名称得分的方法 增量中提到的是指变量得分 make_scoreboard,不是增量中的局部变量。用户和 Python的开发人员表示有兴趣删除它 限制使Python可以具有完全的灵活性 Algol风格的范围模型现在是许多编程中的标准 语言,包括JavaScript,Perl,Ruby,Scheme,Smalltalk,C with GNU扩展和C#2.0。
答案 1 :(得分:2)
Constantinius给出的理由是正确的。处理它的另一种方法(不使用全局变量)将是
def foo(a):
def bar(a):
a -= 1
return a
return bar(a)
>>> print foo(5)
4