当前位置: 首页 > 面试题库 >

为什么“ ord”在这里被视为未分配变量?

毋城
2023-03-14
问题内容

我希望它不是重复的(同时鉴于存在此类错误的问题数量之多,但这是基本错误,同时也很难分辨),但我不明白这里会发生什么。

def f():
    c = ord('a')

f()

运行,没有错误(ord将字符转换为ASCII代码,它是内置的)。现在:

if False:
    ord = None
def f():
    c = ord('a')

f()

也可以运行,没有错误(ord不会被覆盖,条件始终为false)。现在:

def f():
    if False:
        ord = None
    c = ord('a')

f()

我得到(在哪里c = ord('a')

UnboundLocalError: local variable 'ord' referenced before assignment

看起来,即使不运行代码,仅引用左侧操作数也会使其成为局部变量。

显然,我可以解决此问题,但令我感到 非常 惊讶的是,由于python的动态方面允许您定义一个像整数一样的变量,并在下一行将其定义为字符串。

似乎与if语句中初始化的变量的范围有关?

显然,解释器在编译为字节码时仍会记录未到达的分支,但是究竟发生了什么呢?

(在Python 2.7和Python 3.4上测试)


问题答案:

这与编译器在编译为字节码时基于不相关分支进行静态分析无关;这要简单得多。

Python有一个区分全局变量,闭包变量和局部变量的规则。在函数中分配的所有变量(包括隐式分配给参数的参数)都是局部变量(除非它们具有globalornonlocal语句)。参考文档的“绑定和命名”及后续章节对此进行了说明。

这并不是要使解释器简单,而是要使规则足够简单以使人类读者通常可以直观地理解,并且在不直观时可以很容易地被人解决。(这对于此类情况尤其重要-
行为并非到处都是直观的,因此Python将规则保持足够简单,以使一旦学习,该情况仍然很明显。但是您肯定必须在此之前学习该规则是的,当然,大多数人是第一次对规则感到惊讶来学习该规则的…)

即使优化器足够聪明,可以完全删除与之相关的任何字节码if False: ord=Noneord但根据语言语义规则,仍必须是局部变量。

因此:ord =函数中有一个,因此对的所有引用ord都是对局部变量的引用,而不是碰巧具有相同名称的任何全局或非局部变量,因此您的代码是UnboundLocalError

许多人在不了解实际规则的情况下走了过来,而是使用了更简单的规则:变量是

  • 如果可能,则为本地,否则为
  • 如果可能,将其封闭,否则
  • 如果是全局变量,则为全局变量,否则
  • 内置(如果内置),否则
  • 一个错误

尽管这种方法在大多数情况下都有效,但在某些情况下(例如这种情况)可能会产生误导。具有以Lisp样式完成LEGB范围界定的语言会看到它ord不在本地名称空间中,因此会返回全局名称,但Python不会这样做。您可以说这ord

在本地名称空间中,但是绑定到一个特殊的“未定义”值,它实际上接近幕后发生的事情,但这不是Python规则所说的,尽管这样做可能更直观简单的情况下,很难进行推理。

如果您好奇这是如何工作的,请执行以下操作:

在CPython中,编译器将扫描您的函数以查找所有以标识符为目标的赋值,并将其存储在数组中。它删除全局变量和非局部变量。该数组最终将作为您的代码对象的数组co_varnames,因此,假设您ordco_varnames[1]。然后,对该变量的每次使用都会编译为LOAD_FAST 1STORE_FAST 1,而不是编译为LOAD_NAMESTORE_GLOBAL或其他操作。解释时,这LOAD_FAST 1只是将框架的内容加载f_locals[1]到堆栈中。它f_locals以NULL指针数组而不是指向Python对象的指针开始,如果LOAD_FAST加载了NULL指针,它将引发UnboundLocalError



 类似资料:
  • 问题内容: 我应该开发一个简单的SFTP。 一切都进行得很好,直到我(在本例中)没有编写全部为止。可以请我解释一下,为什么系统挂在我身上吗? 服务器端: 客户端: 问题答案: 您的循环一直运行到流结束,但是对等方永远不会关闭套接字。该协议似乎要求打开套接字以供其他命令使用,因此您必须调整它的这一部分以包括一个长度字前缀,以便您知道要复制多少字节。 问题不是关于不写所有字节,而是关于阻塞in 。

  • 问题内容: 我一直在使用IIFE中和,并一直在使用的结构如下: 方法1: 但是,我经常看到以下情况,其中将变量分配给 方法2: 注意: 此问题 不是 关于此模式是什么或IIFE是什么。这与为什么要 在IIFE上 使用返回变量及其与Angular实践的关系有关。 在Angular方法1中工作正常,但是在我看到的许多原始JS示例中,都使用了方法2。我的假设是,封装在其中的任何内容都可以通过它进行调用。

  • 测试代码为: 测试代码为: 你知道怎么了吗?

  • 我遇到JSON解析错误。我的代码如下: 我从我的检查中得到以下错误: 由于:com,无法分析JSON。谷歌。格森。JsonSyntaxException:java。lang.IllegalStateException:应为BEGIN\u对象,但在第1行第2列为BEGIN\u数组 对于我试图读取的JSON,如果成功,我的应该返回5。 我做错了什么?

  • 这是我的线程: 它得到一个上限和下限以及一个在所有线程上共享的结果。 这是我的测试类:

  • 问题内容: 我刚读 ISO / IEC 9899:201x委员会草案-2011年4月12日 在其中我发现5.1.2.2.3程序终止 这表示如果您未在中指定任何return语句,并且如果程序成功运行,则main的右大括号}将返回0。 但是在下面的代码中,我没有指定任何return语句,但是它没有返回0 编译 问题答案: 该规则是在C标准的1999版本中添加的。在C90中,返回的状态未定义。 您可以通