【问题标题】:Python local vs global variablesPython 局部变量与全局变量
【发布时间】:2015-01-18 10:58:59
【问题描述】:

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

a=0

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

test()

【问题讨论】:

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


    【解决方案1】:

    设置和测试

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

    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 上。

    【讨论】:

      【解决方案2】:

      Python 不会在你提交的函数代码中逐行执行。它必须首先将其解析为一个执行块。它决定一个变量是局部的还是全局的,这取决于它是否写在(函数)局部级别。事实上,它决定变量是本地的,因此是错误的。

      【讨论】:

        【解决方案3】:

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

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

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

        【讨论】:

          【解决方案4】:

          简短说明:

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

          更长的解释

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

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

          基于函数字节码的解释

          如果你运行这段代码:

          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 之前。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-07-24
            • 1970-01-01
            • 2015-08-19
            • 2012-09-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多