Python中“全局”变量的意外行为
导致此错误的原因:Python中“全局”变量的意外行为,python,Python,导致此错误的原因: 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") 但是如果我对find的前最后
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")
但是如果我对find
的前最后一行进行注释
if p == '' and prev == h: return prev_re
UnboundLocalError: local variable 'prev' referenced before assignment
$
代码按预期正确运行,没有错误
我的问题是,为什么在第一种情况下它找不到全局变量prev
,为什么在第二种情况下它在if
-条件下找到全局变量
编辑:请帮助我了解环境结构的详细信息,以了解解释程序找不到变量的原因。IINM,Python解释程序检测到变量在函数的后面被分配,因此将其视为本地变量 解决方法是使用一个类,并将prev和prev_re作为该类的实例变量 问题与解决方案 正如MAK所提到的,
prev
被视为本地的,因为您为它赋值(在您检查值之后)。解决方案是将这两个变量显式表示为全局变量:
prev,prev_re=”,(无)#这些是全局变量
def find(h,p='',re=None):
全球预测,预测
打印h、p、re
#global prev,prev#基本上就是你在评论之前所做的
如果p==''和prev==h:返回prev\u re
prev,prev_re=h,re
返回re
打印查找(“abc”)
回答你的问题
为什么在第一种情况下它找不到全局变量prev
它会找到它,但随后会找到前面没有global
语句的赋值。因此,变量被视为局部变量。用global
取消注释该行,它将被修复。或者对局部赋值使用不同的变量。您还可以将该值保存为函数的属性(函数也是对象!)
为什么在第二种情况下,它会在if条件下找到全局变量
它将其视为全局变量(因为您只读取它,而不在函数中定义它,所以它不受局部变量的影响)
更多阅读
当提到这种行为时,您询问了文档中的位置。我没有发现任何地方明确说明错误的含义以及发生这种特定情况的原因,但这可能足够了:
如果名称绑定操作发生在代码块内的任何位置,则块内名称的所有使用都将被视为对当前块的引用。在绑定块之前在块中使用名称时,这可能会导致错误。这条规则很微妙。Python缺少声明,并且允许名称绑定操作发生在代码块中的任何位置。代码块的局部变量可以通过扫描块的整个文本进行名称绑定操作来确定。
如果global语句出现在一个块中,则语句中指定的名称的所有用法都引用顶级命名空间中该名称的绑定。通过搜索全局名称空间(即包含代码块的模块名称空间)和内置名称空间(模块的名称空间)\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。首先搜索全局名称空间。如果在那里找不到名称,则搜索内置名称空间必须在所有使用名称之前使用global
语句
所以基本上:
- 如果赋值发生在特定函数中,变量将被视为局部变量,除非
- 如果变量的使用前面有
global
语句,则该变量被视为局部变量
- 如果没有赋值,则首先在本地名称空间中查找变量,然后在全局名称空间中查找变量,然后在
\uuuuuu builtin\uuuu
模块中搜索变量
还请注意,Python 3有非局部
语句,告诉解释器变量来自外部范围(不是当前范围,但不一定是全局范围)。您没有将prev
声明为全局范围。如果只对变量执行读取操作,python将尝试将该变量视为全局变量。但是,由于您执行赋值,python会检测到这一点,并将prev
作为局部变量
有关更多信息,请参阅。具体而言,该部分说明了以下内容:
将对象分配给单个目标的递归定义为
接着
如果目标是标识符(名称):
- 如果名称未出现在当前代码的全局语句中
block:名称绑定到当前本地命名空间中的对象
- 否则:名称将绑定到当前全局视图中的对象
命名空间
如果希望变量名引用全局变量,则应使用global
语句将其声明为全局变量。使全局变量在函数范围内可用。如果您没有声明全局的东西,Python就无法知道您所指的是全局还是创建新的局部
您得到的错误仅仅意味着Python在设置变量之前已经识别出您正在使用一个变量;即使没有定义全局变量,也会出现相同的错误。这是预期的,但我需要有关环境分配的详细信息。以后分配的意味着什么?我来自c/lisp的方向,从来没有听说过这个概念。@alinsoar它的意思是你把prev\u re=re
放在return prev\u re
之后,所以Python认为你在声明它之前试图使用局部变量prev\u re
。(更多信息请参见Tadeck的答案)我以前遇到过这种行为,从我做出来的我认为通过对全局变量赋值,而不是在函数中将它们显式标记为全局变量,您创建了新的局部变量,在分配它们之前使用的。如果pre==''和prev==h,则没有:返回prev\u re
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")