为什么“ord"在这里被视为未分配的变量? [英] why is 'ord' seen as an unassigned variable here?

查看:33
本文介绍了为什么“ord"在这里被视为未分配的变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望它不是重复的(同时,鉴于此类错误的问题数量很多,因此很难判断,但哪些是基本错误),但我不明白这里发生了什么.

I hope it's not a duplicate (and at the same time it's difficult to tell, given the amount of questions with such errors, but which are basic mistakes), but I don't understand what happens here.

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

f()

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

runs, no error (ord converts character to ASCII code, it's a built-in). Now:

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

f()

也运行,没有错误(ord 不会被覆盖,条件总是假的).现在:

Also runs, no error (ord isn't overwritten, condition is always false). Now:

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

f()

我得到(在 c = ord('a') 处)

UnboundLocalError: local variable 'ord' referenced before assignment

似乎只是引用左侧操作数使其成为局部变量,即使代码没有运行.

It seems that just referencing a left side operand makes it a local variable, even if the code is not run.

显然我可以解决这个问题,但我很非常惊讶,因为 python 的动态方面允许你定义一个变量,比如一个整数,并在下一行将它定义为一个字符串.

Obviously I can workaround this, but I was very surprised, given that the dynamic aspect of python allows you to define a variable like being an integer, and at the next line define it as a string.

似乎与作用域是什么有关在 if 语句中初始化的变量?

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

Apparently the interpreter still takes notes of unreached branches when compiling to bytecode, but what happens exactly?

(在 Python 2.7 和 Python 3.4 上测试)

(tested on Python 2.7 and Python 3.4)

推荐答案

这不是编译器在编译为字节码时根据无关分支进行静态分析;就简单多了.

It's not about the compiler doing a static analysis based on unrelated branches when compiling to bytecode; it's much simpler.

Python 有区分全局、闭包和局部变量的规则.在函数中分配的所有变量(包括隐式分配的参数)都是局部变量(除非它们具有 globalnonlocal 语句).这在 绑定和命名 和后续部分中进行了解释参考文档.

Python has a rule for distinguishing global, closure, and local variables. All variables that are assigned to in the function (including parameters, which are assigned to implicitly), are local variables (unless they have a global or nonlocal statement). This is explained in Binding and Naming and subsequent sections in the reference documentation.

这不是要让解释器保持简单,而是要让规则足够简单,以至于它通常对人类读者来说是直观的,并且在不直观时可以很容易地由人类解决.(这对于这样的情况尤其重要——行为不可能在任何地方都是直观的,所以 Python 保持规则足够简单,一旦你学会了,这样的情况仍然很明显.但你绝对必须在此之前学习规则是的.而且,当然,大多数人是通过第一次就惊讶于它来学习规则的......)

This isn't about keeping the interpreter simple, it's about keeping the rule simple enough that it's usually intuitive to human readers, and can easily be worked out by humans when it isn't intuitive. (That's especially important for cases like this—the behavior can't be intuitive everywhere, so Python keeps the rule simple enough that, once you learn it, cases like this are still obvious. But you definitely do have to learn the rule before that's true. And, of course, most people learn the rule by being surprised by it the first time…)

即使使用足够聪明的优化器来完全删除与 if False: ord=None 相关的任何字节码,根据语言规则,ord 仍然必须是局部变量语义.

Even with an optimizer smart enough to completely remove any bytecode related to if False: ord=None, ord must still be a local variable by the rules of the language semantics.

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

So: there's an ord = in your function, therefore all references to ord are references to a local variable, not any global or nonlocal that happens to have the same name, and therefore your code is an UnboundLocalError.

很多人在不知道实际规则的情况下,而是使用更简单的规则:变量是

Many people get by without knowing the actual rule, and instead use an even simpler rule: a variable is

  • 本地,如果可能的话,否则
  • 尽可能封闭,否则
  • 如果在全局变量中,则为全局,否则为
  • 内置,如果它是内置的,否则
  • 错误

虽然这适用于大多数情况,但在某些情况下可能会有点误导——比如这个.具有 LEGB 范围完成 Lisp 风格的语言会看到 ord 不在本地名称空间中,因此返回全局名称,但 Python 不会这样做.你可以说 ord is 在本地命名空间中,但绑定到一个特殊的未定义"值,这实际上接近幕后发生的事情,但事实并非如此Python 的规则是这样说的,虽然对于简单的情况它可能更直观,但更难推理.

While this works for most cases, it can be a bit misleading in some cases—like this one. A language with LEGB scoping done Lisp-style would see that ord isn't in the local namespace, and therefore return the global, but Python doesn't do that. You could say that ord is in the local namespace, but bound to a special "undefined" value, and that's actually close to what happens under the covers, but that's not what the rules of Python say, and, while it may be more intuitive for simple cases, it's harder to reason through.

如果您想知道它是如何工作的:

If you're curious how this works under the covers:

在 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.

In CPython, the compiler scans your function to find all assignments with an identifier as a target, and stores them in an array. It removes global and nonlocal variables. This arrays ends up as your code object's co_varnames, so let's say your ord is co_varnames[1]. Every use of that variable then gets compiled to a LOAD_FAST 1 or STORE_FAST 1, instead of a LOAD_NAME or STORE_GLOBAL or other operation. That LOAD_FAST 1 just loads the frame's f_locals[1] onto the stack when interpreted. That f_locals starts off as an array of NULL pointers instead of pointers to Python objects, and if a LOAD_FAST loads a NULL pointer, it raises UnboundLocalError.

这篇关于为什么“ord"在这里被视为未分配的变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆