为什么这个对非本地范围的变量引用不会解析?
Why won't this variable reference to a non-local scope resolve?
下面是一个例子,用于查找正整数 a
和 b
以及 a <= b
的最大公约数。我从较小的 a
开始,逐个减去检查它是否是两个数字的约数。
def gcdFinder(a, b):
testerNum = a
def tester(a, b):
if b % testerNum == 0 and a % testerNum == 0:
return testerNum
else:
testerNum -= 1
tester(a, b)
return tester(a, b)
print(gcdFinder(9, 15))
然后,我收到错误消息,
UnboundLocalError: local variable 'testerNum' referenced before assignment
.
使用global testerNum
后,在Spyder控制台成功显示答案3
...
但在pythontutor.com中,它表示NameError: name 'testerNum' is not defined
(link)。
Q1: 在 Spyder 中,我认为 global testerNum
是一个问题,因为 testerNum = a
不在全局范围内。它在函数 gcdFinder
的范围内。这个描述是否正确?如果有,Spyder 是如何显示答案的?
Q2:在pythontutor中,说最后一张截图,如何解决pythontutor中的NameError问题?
Q3:为什么Spyder和pythontutor的结果不一样,哪个是正确的?
Q4:是不是最好不用global
方法?
--
更新:Spyder 问题是由于之前 运行 中存储的值造成的,因此它已被定义为 9
。这使得 global testerNum
起作用了。我已经删除了 Q1 和 Q3。
Q2 和 Q4 的答案。
正如我在评论中所写,您可以将 testerNum 解析为参数。
您的代码将如下所示:
def gcdFinder(a, b):
testerNum = a
def tester(a, b, testerNum):
if b % testerNum == 0 and a % testerNum == 0:
return testerNum
else:
testerNum -= 1
return tester(a, b, testerNum) # you have to return this in order for the code to work
return tester(a, b, testerNum)
print(gcdFinder(9, 15))
编辑:(见评论)
只打第4题,是的,最好不要用global
。 global
通常突出糟糕的代码设计。
你会遇到很多麻烦;我强烈建议您查找计算 GCD 的标准方法,并改用 Euclid 算法。编码细节留给学生作为练习。
问题:
尝试解析变量引用时,Python 首先检查局部作用域,然后检查任何封闭函数的局部作用域。例如这段代码:
def foo():
x=23
def bar():
return x +1
return bar
print(foo()())
将 运行 打印出来 24
因为当 x
在 bar
内部引用时,因为在本地范围内没有 x
它在封闭函数 (foo
) 的范围内找到它。但是,一旦您尝试分配给一个变量,Python 就会假设它是在本地范围内定义的。所以这个:
def foo():
x=23
def bar():
x = x + 1
return x
return bar
print(foo()())
将抛出一个 UnboundLocalError
因为我正在尝试分配给 x
这意味着它将在本地范围内查找,但我试图分配给它的值基于封闭范围中的 x
。由于分配将 x
的搜索限制在本地范围内,因此无法找到它,我收到错误消息。
所以你的错误出现是因为你的 else 子句中的 testerNum -= 1
行,它将 testerNum
的搜索限制在它不存在的本地范围内。
修复:
global
声明不正确,因为正如您所指出的,testerNum
未在全局范围内定义。我不熟悉 Spyder,也不知道它为什么在那里工作,但它似乎以某种方式在其全局范围内获得了一个 testerNum
变量。
如果您正在使用 Python3,您可以通过将 global testerNum
行更改为 nonlocal testerNum
来解决此问题,这只是告诉 Python 尽管被分配给, testerNum 未在本地范围内定义并继续向外搜索。
def foo():
x=23
def bar():
nonlocal x
x = x + 1
return x
return bar
>>> print(foo()())
24
在 Python 2 或 3 中可行的另一个选项是绕过 testerNum
,正如 Brambor 在他们的回答中概述的那样。
下面是一个例子,用于查找正整数 a
和 b
以及 a <= b
的最大公约数。我从较小的 a
开始,逐个减去检查它是否是两个数字的约数。
def gcdFinder(a, b):
testerNum = a
def tester(a, b):
if b % testerNum == 0 and a % testerNum == 0:
return testerNum
else:
testerNum -= 1
tester(a, b)
return tester(a, b)
print(gcdFinder(9, 15))
然后,我收到错误消息,
UnboundLocalError: local variable 'testerNum' referenced before assignment
.
使用global testerNum
后,在Spyder控制台成功显示答案3
...
但在pythontutor.com中,它表示NameError: name 'testerNum' is not defined
(link)。
Q1: 在 Spyder 中,我认为 global testerNum
是一个问题,因为 testerNum = a
不在全局范围内。它在函数 gcdFinder
的范围内。这个描述是否正确?如果有,Spyder 是如何显示答案的?
Q2:在pythontutor中,说最后一张截图,如何解决pythontutor中的NameError问题?
Q3:为什么Spyder和pythontutor的结果不一样,哪个是正确的?
Q4:是不是最好不用global
方法?
--
更新:Spyder 问题是由于之前 运行 中存储的值造成的,因此它已被定义为 9
。这使得 global testerNum
起作用了。我已经删除了 Q1 和 Q3。
Q2 和 Q4 的答案。
正如我在评论中所写,您可以将 testerNum 解析为参数。
您的代码将如下所示:
def gcdFinder(a, b):
testerNum = a
def tester(a, b, testerNum):
if b % testerNum == 0 and a % testerNum == 0:
return testerNum
else:
testerNum -= 1
return tester(a, b, testerNum) # you have to return this in order for the code to work
return tester(a, b, testerNum)
print(gcdFinder(9, 15))
编辑:(见评论)
只打第4题,是的,最好不要用global
。 global
通常突出糟糕的代码设计。
你会遇到很多麻烦;我强烈建议您查找计算 GCD 的标准方法,并改用 Euclid 算法。编码细节留给学生作为练习。
问题:
尝试解析变量引用时,Python 首先检查局部作用域,然后检查任何封闭函数的局部作用域。例如这段代码:
def foo():
x=23
def bar():
return x +1
return bar
print(foo()())
将 运行 打印出来 24
因为当 x
在 bar
内部引用时,因为在本地范围内没有 x
它在封闭函数 (foo
) 的范围内找到它。但是,一旦您尝试分配给一个变量,Python 就会假设它是在本地范围内定义的。所以这个:
def foo():
x=23
def bar():
x = x + 1
return x
return bar
print(foo()())
将抛出一个 UnboundLocalError
因为我正在尝试分配给 x
这意味着它将在本地范围内查找,但我试图分配给它的值基于封闭范围中的 x
。由于分配将 x
的搜索限制在本地范围内,因此无法找到它,我收到错误消息。
所以你的错误出现是因为你的 else 子句中的 testerNum -= 1
行,它将 testerNum
的搜索限制在它不存在的本地范围内。
修复:
global
声明不正确,因为正如您所指出的,testerNum
未在全局范围内定义。我不熟悉 Spyder,也不知道它为什么在那里工作,但它似乎以某种方式在其全局范围内获得了一个 testerNum
变量。
如果您正在使用 Python3,您可以通过将 global testerNum
行更改为 nonlocal testerNum
来解决此问题,这只是告诉 Python 尽管被分配给, testerNum 未在本地范围内定义并继续向外搜索。
def foo():
x=23
def bar():
nonlocal x
x = x + 1
return x
return bar
>>> print(foo()())
24
在 Python 2 或 3 中可行的另一个选项是绕过 testerNum
,正如 Brambor 在他们的回答中概述的那样。