2

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.

使用后,在 Spyder 控制台中global testerNum成功显示答案...3

间谍的结果

但在 pythontutor.com 中,它说NameError: name 'testerNum' is not defined链接)。

pythontutor的结果

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

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

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

Q4:不使用global方法更好吗?

--

更新: Spyder 问题是由于先前运行存储的值,因此它9已被定义。这就是global testerNum工作。我已经删除了 Q1 和 Q3。

4

3 回答 3

5

问题:

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

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

print(foo()())

将运行并打印出来,24因为 whenx在 内部被引用bar,因为x在本地范围内没有它在封闭函数 ( foo) 的范围内找到它。但是,一旦您尝试分配一个变量,Python 就会假定它是在本地范围内定义的。所以这:

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

print(foo()())

将抛出一个,UnboundLocalError因为我正在尝试分配,x这意味着它将在本地范围内查找,但我试图分配给它的值是基于x封闭范围的。由于分配将搜索限制在x本地范围内,因此无法找到它并且我收到错误消息。

因此,由于testerNum -= 1else 子句中的行而出现错误,它将搜索限制在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 在他们的答案中概述的方式传递。

于 2018-02-01T17:53:06.333 回答
2

Q2Q4的答案。

正如我在评论中所写,您可以将 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))

编辑:(见评论)

于 2018-02-01T17:28:31.233 回答
0

只打第4题,是的,最好不要使用globalglobal通常会突出糟糕的代码设计。

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

于 2018-02-01T17:33:05.777 回答