为什么此变量引用不会解析非本地范围?

时间:2018-02-01 17:13:59

标签: python python-3.x scope spyder global-scope

以下是查找正整数ab以及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 ...

spyder's outcome

但是在pythontutor.com中,它说NameError: name 'testerNum' is not definedlink)。

pythontutor's outcome

Q1:在Spyder中,我认为global testerNum是一个问题,因为testerNum = a不在全球范围内。它在函数gcdFinder的范围内。这种描述是否正确?如果是这样,Spyder是如何显示答案的?

Q2:在pythontutor中,说最后的截图,如何解决pythontutor中的NameError问题?

Q3:为什么Spyder和pythontutor的结果有差异,哪个是正确的?

问题4:最好不要使用global方法吗?

-

更新:Spyder问题是由于之前运行时存储的值,因此它已经定义为9。这使global testerNum工作。我删除了Q1&amp; Q3。

3 个答案:

答案 0 :(得分:4)

问题:

在尝试解析变量引用时,Python首先检查本地作用域,然后检查任何封闭函数的本地作用域。例如这段代码:

def foo():
    x=23
    def bar():
        return x +1
    return bar

print(foo()())

将运行并打印24,因为x内引用了bar,因为本地范围内没有x,它会在foo范围内找到它封闭函数(def foo(): x=23 def bar(): x = x + 1 return x return bar print(foo()()) )。但是,只要您尝试分配给变量,Python就会假定它是在本地范围内定义的。所以这个:

UnboundLocalError

将抛出x,因为我试图分配给x,这意味着它将在本地范围内被查找,但我试图分配给它的值是基于的来自封闭范围的x。由于分配将testerNum -= 1的搜索范围限制为本地范围,因此无法找到它并且我收到错误。

因此,由于您的else子句中的testerNum行,您的错误即将出现,它将global的搜索限制在不存在的本地范围内。

修复:

testerNum声明不正确,因为正如您所指出的那样,testerNum未在全局范围内定义。我不熟悉Spyder并且不知道为什么它在那里工作但似乎它在某种程度上在其全局范围内得到了global testerNum变量。

如果您正在使用Python3,可以通过将nonlocal testerNum行更改为def foo(): x=23 def bar(): nonlocal x x = x + 1 return x return bar >>> print(foo()()) 24 来解决这个问题,而testerNum只告诉Python,尽管已经分配了,但却没有在本地范围内定义testerNum,继续向外搜索。

npm install rxjs

在Python 2或3中可以使用的另一个选项是传递server.ts作为Brambor在答案中概述的内容。

答案 1 :(得分:2)

回答 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))

编辑:(见注释)

答案 2 :(得分:0)

仅针对问题4,是的,最好不要使用globalglobal通常会突出代码设计不佳。

你会遇到很多麻烦;我强烈建议您查找计算GCD的标准方法,并改为实现Euclid算法。编码细节留给学生练习。