【问题标题】:Why won't this variable reference to a non-local scope resolve?为什么这个变量对非本地范围的引用不能解析?
【发布时间】:2018-02-01 17:13:58
【问题描述】:

这是一个为正整数 aba <= 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。

【问题讨论】:

  • 不回答您的任何问题,我认为将 testerNum 解析为参数会更好,因此将定义函数 testerdef tester(a, b, testerNum)
  • 实际上是对您的问题 2 和 4 的回答:D
  • 示例代码中testNum不是global。尝试改用关键字nonlocal。这假设您使用的是 python3。

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


【解决方案1】:

问题:

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

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

print(foo()())

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

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

print(foo()())

将抛出一个UnboundLocalError,因为我正在尝试分配给x,这意味着它将在本地范围内查找,但我尝试分配给它的值是基于@987654330 @ 来自封闭范围。由于该分配将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 在他们的回答中概述的那样。

【讨论】:

  • 谢谢,解释得很清楚,尤其是第三段。
  • 所以我可以说,在函数外调用变量是可以的,但是如果我想改变它,那是行不通的。
  • @chenghuayang 正确,除非你可以声明nonlocal
  • nonlocal 也不推荐吗?它要求计算机向外搜索,这会消耗一些处理。
  • @chenghuayang 它不会消耗您所注意到的任何处理能力。至于它是否是坏的形式,那肯定是见仁见智的问题。我认为在某些情况下它可能很有用,但它肯定会引起一些混乱,并且作为一般做法避免使用可能更安全
【解决方案2】:

Q2Q4 的答案。

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

编辑:(见评论)

【讨论】:

  • 这解决了问题。谢谢。但是如果我在函数外部设置一个变量,同时在函数内部设置它作为参数,会不会很奇怪?
  • 我不太确定你的意思。如果您关心的是代码a = 5; def double(x): return x*2; print(double(a))。如果它在您的代码中与 xa 重叠,那么不,它并不奇怪
  • 好的,知道了。最好用不同的词。
【解决方案3】:

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

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

【讨论】:

猜你喜欢
  • 2013-06-03
  • 1970-01-01
  • 1970-01-01
  • 2011-12-14
  • 1970-01-01
  • 1970-01-01
  • 2012-04-01
  • 1970-01-01
  • 2016-08-19
相关资源
最近更新 更多