Python本地变量和全局变量

时间:2014-03-16 16:47:21

标签: python scope runtime global-variables local-variables

我理解Python中局部变量和全局变量的概念,但我只是问一下为什么错误会出现在下面的代码中。 Python逐行执行代码,因此在读取第5行之前,它不知道a是局部变量。在尝试执行第5行后,Python是否会返回一行并将其标记为错误?

a=0

def test():
    print a  #line 4, Error : local variable 'a' referenced before assignment
    a=0      #line 5

test()

4 个答案:

答案 0 :(得分:12)

设置和测试

要分析您的问题,让我们创建两个独立的测试函数来复制您的问题:

a=0

def test1():
    print(a)

test1()

打印0。因此,调用此函数不是问题,而是在下一个函数上:

def test2():
    print(a)  # Error : local variable 'a' referenced before assignment
    a=0  

test2()

我们收到错误:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in test2
UnboundLocalError: local variable 'a' referenced before assignment

<强>拆卸

我们可以反汇编这两个函数(第一个 Python 2 ):

>>> import dis
>>> dis.dis(test1)
  2           0 LOAD_GLOBAL              0 (a)
              3 PRINT_ITEM          
              4 PRINT_NEWLINE       
              5 LOAD_CONST               0 (None)
              8 RETURN_VALUE        

我们看到第一个函数自动加载全局a,而第二个函数:

>>> dis.dis(test2)
  2           0 LOAD_FAST                0 (a)
              3 PRINT_ITEM          
              4 PRINT_NEWLINE       

  3           5 LOAD_CONST               1 (0)
              8 STORE_FAST               0 (a)
             11 LOAD_CONST               0 (None)
             14 RETURN_VALUE      

看到在其中分配a,尝试从本地进行LOAD_FAST(作为优化,因为函数在运行之前被预编译为字节代码。)

如果我们在 Python 3 中运行它,我们会看到几乎相同的效果:

>>> test2()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in test2
UnboundLocalError: local variable 'a' referenced before assignment
>>> 
>>> import dis
>>> dis.dis(test1)
  2           0 LOAD_GLOBAL              0 (print) 
              3 LOAD_GLOBAL              1 (a) 
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair) 
              9 POP_TOP              
             10 LOAD_CONST               0 (None) 
             13 RETURN_VALUE     

>>> dis.dis() # disassembles the last stack trace
  2           0 LOAD_GLOBAL              0 (print) 
    -->       3 LOAD_FAST                0 (a) 
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair) 
              9 POP_TOP              

  3          10 LOAD_CONST               1 (0) 
             13 STORE_FAST               0 (a) 
             16 LOAD_CONST               0 (None) 
             19 RETURN_VALUE        

我们再次看到错误在LOAD_FAST上。

答案 1 :(得分:6)

Python不会在您提交的功能代码中逐行执行。它首先将其解析为执行块。它决定变量是局部变量还是全局变量,具体取决于它是否写入(函数)本地级别。在这种情况下,它决定变量是本地的,因此是错误。

答案 2 :(得分:4)

这是因为,在python中,您需要告诉您要修改全局变量的值。你那样做:

def test():
  global a
  print a  #line 4, Error : local variable 'a' referenced before assignment
  a=0      #line 5

使用global a,您可以修改函数中的变量。 你可能想看看这个:

答案 3 :(得分:3)

简短说明:

a变量绑定到test函数。当您尝试打印它时,Python会抛出错误,因为稍后将初始化本地变量a。但是如果删除a=0,代码将毫无问题地执行并输出0。

更长的解释

Python解释器开始从本地范围搜索名为a的变量。它看到a确实在函数中声明并且仅在第五行初始化。一旦找到,查找就结束了。

当它试图处理print a(第四行)时,它说'哦,男孩,我需要打印一个尚未初始化的变量,我最好抛出一个错误。&#39;

基于功能的字节码

的说明

如果您运行此代码:

import dis

a = 0

def test():
  print a  #line 4, Error : local variable 'a' referenced before assignment
  a = 0    #line 5

dis.dis(test)

您将获得此输出:

  6           0 LOAD_FAST                0 (a)
              3 PRINT_ITEM          
              4 PRINT_NEWLINE       

  7           5 LOAD_CONST               1 (0)
              8 STORE_FAST               0 (a)
             11 LOAD_CONST               0 (None)
             14 RETURN_VALUE        

对上述不清楚部分的解释:

  • LOAD_FAST表示a的引用被推入堆栈。
  • STORE_FAST表示Python将0(从LOAD_CONST)分配给局部变量a

所以,问题是LOAD_FAST在STORE_FAST之前。