• 变量作用域规则


    全局变量

    定义一个函数,它读取两个变量的值:一个是局部变量a,是函数的参数,另一个是变量b,这个函数没有定义它

    def f1(a):
        print(a)
        print(b)
    
    print(f1(3))
    
    
    # 运行结果
    3
    Traceback (most recent call last):
      File "E:/virtual_workshop/everyday/test/f1.py", line 6, in <module>
        print(f1(3))
      File "E:/virtual_workshop/everyday/test/f1.py", line 3, in f1
        print(b)
    NameError: name 'b' is not defined
    

    出现这样的错误并不奇怪,因为全局变量b并没有赋值,使用dis反汇编一下,可以看到是往栈里load了全局变量b

    from dis import dis
    
    print(dis(f1))
    
    
    # 运行结果
     2           0 LOAD_GLOBAL              0 (print)
                  2 LOAD_FAST                0 (a)
                  4 CALL_FUNCTION            1
                  6 POP_TOP
    
      3           8 LOAD_GLOBAL              0 (print)
                 10 LOAD_GLOBAL              1 (b)   #往栈里load了全局变量b
                 12 CALL_FUNCTION            1
                 14 POP_TOP
                 16 LOAD_CONST               0 (None)
                 18 RETURN_VALUE
    None
    

    怎么优化这个程序?只需要先给全局变量b赋值,然后再调用f

    def f1(a):
        print(a)
        print(b)
    
    b = 6
    print(f1(3))
    
    
    # 运行结果
    3
    6
    None
    

    局部变量

    下面的f2函数,先给b赋值,然后再打印a和b的值

    b = 6
    
    def f2(a):
        print(a)
        print(b)
        b = 9   #局部变量
    
    print(f2(3))
    
    
    # 运行结果
    3
    Traceback (most recent call last):
      File "E:/virtual_workshop/everyday/test/f2.py", line 9, in <module>
        print(f2(3))
      File "E:/virtual_workshop/everyday/test/f2.py", line 6, in f2
        print(b)
    UnboundLocalError: local variable 'b' referenced before assignment
    

    为什么会出现这样的情况呢,因为Python编译函数的时候,它判定b是局部变量,因为在函数中给它赋值了。生成的字节码正事了这种判断,Python会尝试从本地环境获取b。后面调用f2(3)时,f2的定义体会获取并打印局部变量a的值,但是尝试获取局部变量b的值时,发现b没有绑定值。这不是缺陷,而是设计选择:Python不要求声明变量,但是假定在函数体中赋值的变量是局部变量。使用dis反汇编一下,可以看到加载的b是局部变量

      5           0 LOAD_GLOBAL              0 (print)
                  2 LOAD_FAST                0 (a)
                  4 CALL_FUNCTION            1
                  6 POP_TOP
    
      6           8 LOAD_GLOBAL              0 (print)
                 10 LOAD_FAST                1 (b)   #往栈里load了局部变量b
                 12 CALL_FUNCTION            1
                 14 POP_TOP
    
      7          16 LOAD_CONST               1 (9)
                 18 STORE_FAST               1 (b)
                 20 LOAD_CONST               0 (None)
                 22 RETURN_VALUE
    None
    

    如果在函数中赋值时想让解释器把b当做全局变量,需要用global声明:

    b = 6
    
    def f2(a):
        global b
        print(a)
        print(b)
        b = 9   #局部变量
    
    
    # 运行结果
    3
    6
    None
    

    参考书籍

    《流畅的Python》

  • 相关阅读:
    【mpeg2】MPEG-2官方参考代码MPEG2_reference_software
    【base】Copyright 与 Copyleft
    【base】Copyright 与 Copyleft
    【complier】如何查看ARM交叉编译的可执行程序依赖的动态库?
    【shell系列】之查看shell脚本的执行过程和makefile中调试手段
    【tools】一款强大的局部搜索工具:xsearch
    【tools】一款强大的局部搜索工具:xsearch
    【mpeg2】mpeg2编码器的开源实现:x262
    【mpeg2】mpeg2解码器开源实现:libmpeg2
    【codecs】视频显示分辨率格式分析
  • 原文地址:https://www.cnblogs.com/my_captain/p/12843358.html
Copyright © 2020-2023  润新知