2
prev, prev_re = '', (None) # these are globals

def find(h, p='', re=None):
    print h, p, re
    #global prev, prev_re
    if p == '' and prev == h: return prev_re
    prev, prev_re = h, re
    return re
print find ("abc")

导致此错误:

    if p == '' and prev == h: return prev_re
UnboundLocalError: local variable 'prev' referenced before assignment
$ 

如果我评论前最后一行find

prev, prev_re = '', (None)

def find(h, p='', re=None):
    print h, p, re
    #global prev, prev_re
    if p == '' and prev == h: return prev_re
    #prev, prev_re = h, re
    return re
print find ("abc")

代码按预期正确运行,没有错误。

我的问题是为什么在第一种情况下它没有找到全局变量 prev,为什么在第二种情况下它确实在if-condition 中找到了全局变量?

编辑:请帮助我了解环境结构的详细信息,以了解解释器为什么找不到变量。

4

4 回答 4

7

问题与解决方案

正如 MAK 所提到的,prev被视为本地,因为您为其分配了值(在您检查值之后)。解决方案是将这两个变量显式声明为全局变量:

prev, prev_re = '', (None) # these are globals

def find(h, p='', re=None):
    global prev, prev_re
    print h, p, re
    #global prev, prev_re  # basically what you have done before commenting this
    if p == '' and prev == h: return prev_re
    prev, prev_re = h, re
    return re
print find ("abc")

回答您的问题

为什么在第一种情况下它没有找到全局变量 prev

它找到了它,但随后它找到了之前没有global声明的赋值。因此,该变量被视为local。取消注释该行,global它将被修复。或者使用不同的变量进行局部赋值。您还可以将值保存为函数的属性(函数也是对象!)。

为什么在第二种情况下它确实在 if 条件中找到了全局变量

它将它视为全局(因为您只读取它并且没有在函数中定义它,因此它不会被局部变量遮蔽)。

更多阅读

当提到此行为时,您要求在文档中的位置。我没有找到任何地方明确说明错误的含义以及为什么会发生这种特定情况,但是对执行模型有很好的解释可能就足够了:

如果名称绑定操作发生在代码块中的任何位置,则块中名称的所有使用都被视为对当前块的引用。如果在绑定之前在块中使用名称,这可能会导致错误。 这个规则很微妙。Python 缺少声明,并允许名称绑定操作在代码块中的任何位置发生。代码块的局部变量可以通过扫描块的整个文本以进行名称绑定操作来确定。

如果 global 语句出现在一个块中,则该语句中指定的名称的所有使用都指的是该名称在顶级名称空间中的绑定。通过搜索全局命名空间(即包含代码块的模块的命名空间)和内置命名空间(模块的命名空间)来解析顶级命名空间中的名称__builtin__。首先搜索全局命名空间。如果在那里找不到名称,则搜索内置名称空间。global语句必须在名称的所有使用之前

所以基本上:

  • 如果分配发生在特定函数中,则变量被视为local,除非...
  • 如果变量的使用前面有global语句,则变量被视为local
  • 如果没有赋值,首先在本地命名空间中查找变量,然后在全局命名空间中查找,然后在__builtin__模块中查找,

另请注意,Python 3 有nonlocal一条语句告诉解释器该变量来自外部范围(不是当前范围,但不一定是全局范围)。

于 2012-12-28T02:47:15.260 回答
4

您没有声明prev为全局。如果您只对变量执行读取操作,python 将尝试将变量视为全局变量。但是,因为您进行了赋值,python 会检测到这一点并创建prev一个局部变量。

有关详细信息,请参阅http://docs.python.org/2/reference/simple_stmts.html#assignment-statements。具体来说,说明以下内容的部分:

将对象分配给单个目标的递归定义如下。

如果目标是标识符(名称):

  • 如果名称没有出现在当前代码块中的全局语句中:名称绑定到当前本地命名空间中的对象。
  • 否则:名称绑定到当前全局命名空间中的对象。

如果您打算让变量名引用全局变量,则应使用语句将其声明为全局变量global

于 2012-12-28T02:49:33.573 回答
3

global语句使全局变量在函数范围内可用。如果您不声明全局的东西,Python 无法知道您指的是全局还是创建新的本地。

The error you're getting just means that Python has recognized you're using a variable before setting it; you'd get the same error even if the global variables weren't defined at all.

于 2012-12-28T02:50:51.647 回答
2

IINM,Python 解释器检测到该变量在函数的后面被分配,因此将其视为本地变量。

一种解决方法是使用一个类并将 prev 和 prev_re 作为类的实例变量。

于 2012-12-28T02:41:02.973 回答