Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么是';作战需求文件';在这里被视为未赋值变量?_Python_Variables - Fatal编程技术网

Python 为什么是';作战需求文件';在这里被视为未赋值变量?

Python 为什么是';作战需求文件';在这里被视为未赋值变量?,python,variables,Python,Variables,我希望这不是一个重复(同时,考虑到有这么多的问题有这样的错误,很难说出来,但哪些是基本的错误),但我不明白这里发生了什么 def f(): c = ord('a') f() 运行,无错误(ord将字符转换为ASCII码,它是内置的)。现在: 同时运行,无错误(ord未被覆盖,条件始终为false)。现在: 我得到(在c=ord('a')的第行) 似乎只要引用左侧操作数就可以使其成为局部变量,即使代码没有运行 显然我可以解决这个问题,但我非常惊讶,因为python的动态特性允许您定义一

我希望这不是一个重复(同时,考虑到有这么多的问题有这样的错误,很难说出来,但哪些是基本的错误),但我不明白这里发生了什么

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

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

同时运行,无错误(
ord
未被覆盖,条件始终为false)。现在:

我得到(在
c=ord('a')
的第行)

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

显然我可以解决这个问题,但我非常惊讶,因为python的动态特性允许您定义一个变量,比如整数,然后在下一行将其定义为字符串

这似乎与

显然,当编译成字节码时,解释器仍然会记录未到达的分支,但是到底发生了什么呢


(在Python2.7和Python3.4上测试)

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

Python有一个区分全局变量、闭包变量和局部变量的规则。函数中分配给的所有变量(包括隐式分配给的参数)都是局部变量(除非它们具有
global
nonlocal
语句)。这将在参考文档中及其后的章节中进行解释

这不是让解释器保持简单,而是让规则保持足够简单,使其对人类读者来说通常是直观的,当它不是直观的时候,人类可以很容易地解决。(这对于这种情况尤其重要,因为行为不可能处处都是直观的,所以Python将规则保持得足够简单,一旦你学会了,这种情况仍然是显而易见的。但你肯定必须先学会规则,然后才知道这是真的。当然,大多数人在第一次学习规则时都会感到惊讶……)

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

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


许多人在不知道实际规则的情况下就成功了,而是使用了一个更简单的规则:变量是

  • 如果可能,则为本地,否则为
  • 如果可能,则将其封闭,否则
  • 如果是全局的,则为全局的,否则为全局的
  • 如果是内置的,则为内置的,否则为
  • 错误
虽然这适用于大多数情况,但在像这样的一些情况下可能有点误导。具有LEGB作用域done Lisp风格的语言将看到
ord
不在本地名称空间中,因此返回全局名称空间,但Python不会这样做。您可以说,
ord
位于本地名称空间中,但绑定到一个特殊的“未定义”值,这实际上接近于在封面下发生的情况,但这不是Python的规则所说的,而且,虽然对于简单的情况可能更直观,但很难进行推理


如果您想知道这在封面下是如何工作的:


在CPython中,编译器扫描您的函数以查找以标识符为目标的所有赋值,并将它们存储在数组中。它删除全局和非局部变量。这个数组最终成为代码对象的
co\u varnames
,因此假设您的
ord
co\u varnames[1]
。然后,该变量的每次使用都会被编译为
LOAD\u FAST 1
STORE\u FAST 1
,而不是
LOAD\u NAME
STORE\u GLOBAL
或其他操作。当解释时,
LOAD_FAST 1
仅将帧的
f_局部变量[1]
加载到堆栈上。
f_locals
以空指针数组开始,而不是指向Python对象的指针,如果
LOAD\u FAST
加载空指针,它会引发
UnboundLocalError

以演示编译器的运行情况:

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

  4           0 LOAD_FAST                0 (ord)
              3 LOAD_CONST               1 ('a')
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
              9 STORE_FAST               1 (c)
             12 LOAD_CONST               0 (None)
             15 RETURN_VALUE
使用用于局部变量的
LOAD\u FAST
访问
a

如果在功能外将
ord
设置为无,则使用
LOAD\u GLOBAL

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

  4           0 LOAD_GLOBAL              0 (ord)
              3 LOAD_CONST               1 ('a')
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
              9 STORE_FAST               0 (c)
             12 LOAD_CONST               0 (None)
             15 RETURN_VALUE

这已经被问过很多次了。Python中的编译器静态地确定局部变量。分配给的每个名称在编译时都标记为局部变量。将
global ord
放在函数前面可以避免错误。@彼得伍德我不是在问如何修复它,我是在问一个解释。@Jean-Françoisfare我是在向部分解释添加缺失的信息。这是一匹礼物马。无论如何,谢谢你。我知道你想帮忙。使规则有些不直观的部分是,即使
ord+=1
也会呈现
ord
一个局部变量,尽管除非函数中有另一个
ord
赋值,否则这是没有意义的。@SvenMarnach这正是“足够简单,以便在不直观的情况下轻松解决”这一部分非常重要。你必须学习规则,但一旦学习,就很难出错。值得一提的是,我认为这一规则是必要的,因为局部变量是通过索引而不是字典查找(用于全局变量)来访问的。否则,Python可以简单地执行动态查找–首先查找本地范围,如果找不到名称,则查找封闭范围。由于本地变量是按索引而不是按名称查找的,因此编译器需要静态地确定哪些变量是本地变量
UnboundLocalError: local variable 'ord' referenced before assignment
def f():
    if False:
        ord = None
    c = ord('a')

  4           0 LOAD_FAST                0 (ord)
              3 LOAD_CONST               1 ('a')
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
              9 STORE_FAST               1 (c)
             12 LOAD_CONST               0 (None)
             15 RETURN_VALUE
if False:
    ord = None
def f():
    c = ord('a')

  4           0 LOAD_GLOBAL              0 (ord)
              3 LOAD_CONST               1 ('a')
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
              9 STORE_FAST               0 (c)
             12 LOAD_CONST               0 (None)
             15 RETURN_VALUE