• python 本地变量和全局变量 locals() globals() global nonlocal 闭包 以及和 scala 闭包的区别


    最近看 scala ,看到了它的作用域,特此回顾一下python的变量作用域问题。

    A = 10
    B = 100
    print A  #10
    print globals()  #{'A': 10, 'B': 100, '__builtins__': <module '__builtin__' (built-in)>, '__file__': 'E:/PycharmProjects/untitled/test1.py', '__package__': None, '__name__': '__main__', '__doc__': None}
    
    def mu(x,y):
        B = 9 
        print locals()  #{'y': 9, 'x': 10,'B':9}
        if A == 10:
            B = 19
            print locals() #{'y':9,'x':10,'B':19}
            return x+y
        else:
            return x-y
    
    m = mu(10,9)
    print(m)  # 19
    print locals()  #{'A': 10, 'B': 100, '__builtins__': <module '__builtin__' (built-in)>, '__file__': 'E:/PycharmProjects/untitled/test1.py', 'm': 19, '__package__': None, 'mu': <function mu at 0x02ADA430>, '__name__': '__main__', '__doc__': None}
    print globals()#{'A': 10, 'B': 100, '__builtins__': <module '__builtin__' (built-in)>, '__file__': 'E:/PycharmProjects/untitled/test1.py', 'm': 19, '__package__': None, 'mu': <function mu at 0x02ADA430>, '__name__': '__main__', '__doc__': None}  # 全局作用域的 locals 和globals 内的变量内容是一样的。
    print __name__  #  __main__      
    print __file__   #E:/PycharmProjects/untitled/test1.py
    print __doc__ # None
    print __package__ # None
    
    print B  # 100
    
    

    global

    
    A = 10
    B = 100
    print A # 10
    print globals()#{'A': 10, 'B': 100, '__builtins__': <module '__builtin__' (built-in)>, '__file__': 'E:/PycharmProjects/untitled/test1.py', '__package__': None, '__name__': '__main__', '__doc__': None}
    
    def mu(x,y):
        global B
        B +=1
        print(B)  #101
        print locals()  #{'y': 9, 'x': 10}   进过global 作用, 本地变量中不会创建新的本地变量 B 了。而是直接用的全局的 B。
        if A == 10:
            B = 20
            print locals()  #{'y': 9, 'x': 10}  
            return x+y
        else:
            return x-y
    
    m = mu(10,9)
    print(m)
    print locals() #{'A': 10, 'B': 20, '__builtins__': <module '__builtin__' (built-in)>, '__file__': 'E:/PycharmProjects/untitled/test1.py', 'm': 19, '__package__': None, 'mu': <function mu at 0x02A8A430>, '__name__': '__main__', '__doc__': None}
    
    print globals()#{'A': 10, 'B': 20, '__builtins__': <module '__builtin__' (built-in)>, '__file__': 'E:/PycharmProjects/untitled/test1.py', 'm': 19, '__package__': None, 'mu': <function mu at 0x02A8A430>, '__name__': '__main__', '__doc__': None}
    
    print B#20 因为函数中使用了 global 关键字, 函数中使用的是全局变量B ,并且对其做出了修改,所以这个B也就变成了 20
    
    

    赋值 操作

    A = 10
    B = 100
    print A
    print globals()
    
    def mu(x,y):
        # B  = B +1 # 这么做会报错 因为赋值操作会查找 本地变量 然而本地变量中并没有B 变量  并不是想象中的     B =  100 +1 ,只要出现赋值语句,就会遮蔽外层变量,而在此之前,本地变量中并未定义B。
    # print(B)   #100
        print locals()
        if A == 10:
            if B == 100:   #这么做不会报错,它会查找到全局变量
                print "haha"
                print locals()  #{'y': 9, 'x': 10}
            return x+y
        else:
            return x-y
    
    m = mu(10,9)
    print(m)
    print locals()
    print globals()
    print B  #100
    

    以下为python3 操作

    >>> def a(x):
    ...     print(x)
    ...     def b():
    ...         print(x)  # 参数作用域,父函数的参数可以 被子函数所使用,这也就是闭包。scala 作用域与此效果类似,内部函数,可以直接使用外部函数的变量。
    ...     b()
    ... 
    >>> 
    >>> a(10)
    10
    10
    >>> def a(x):
    ...     print(x)
    ...     def b():
    ...         print(x) #这里会报错,因为在一旦在函数内部出现赋值操作,那么就会对外层的变量产生遮蔽效果,无论这赋值参数在本函数内部的位置是否在前,或者是在后,只要出现,就会出现遮蔽效果,此时如果在赋值操作之前使用该变量,就会出现未定义该变量的错误。 scala 的变量作用域效果与此类似。
    ...         x = 20
    ...         print(x)
    ...     b()
    ... 
    >>> a(10)
    10
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 7, in a
      File "<stdin>", line 4, in b
    UnboundLocalError: local variable 'x' referenced before assignment
    >>> def a(x):
    ...     print(x)
    ...     def b():
    ...         nonlocal x #python3 的 nonlocal 语句可以内部函数直接使用外部函数
    ...         x = 20 
    ...         print(x)
    ...     b()
    ...     print(x)
    ... 
    >>> a(10)
    10
    20
    20
    
    
    >>> def a(x):
    ...     print(locals())
    ...     def b():
    ...         print(x)
    ...         print(locals()) 
    ...     b()
    ... 
    >>> a(1)
    {'x': 1}
    1
    {'x': 1}
    >>> def a(x):
    ...     print(locals())
    ...     def b():
    ...         print(locals())  #虽然赋值操作在本打印语句之后,但是仍然 可以看出,x 已经被遮蔽了
    ...         x = 20    #由于未使用nonlocal,此时的x 是一个和外部x 同名的全新的本地变量,所以,对他的任何修改,仅限于本函数内部,不会影响到外部。
    ...         print(locals())
    ...         print(x)
    ...     b()
    ...     print(x)  # 这是 遮蔽效果的证明   
    ... 
    >>> a(10)
    {'x': 10}
    {}
    {'x': 20}
    20
    10   
    >>> 
    
    
    
    

    闭包

    def a():
        x = 20
        def b(y):
            return y+x # 注意闭包内部是直接使用 外层函数的变量,而没有对外层函数变量进行赋值操作。
        return b(10)
    
    
    
    
    
    def c():
        x = 20
        def b(y):
            x += 12  # 这里对x 进行了赋值操作。 x  = x+12 ,这会报错,这其实已经不是闭包了,由于出现了赋值操作,所以,这里的 x 是一个和外层同名的变量,但是在本函数内部,本等式之前,并未进行 x 的宣告。所以会报错
            return x +y
        return  b(10)
    
    print(c())
    

    贴一段scala 的闭包代码:

    object PackageStudy {
      def main(args: Array[String]): Unit = {
        def a(): Int = {
          var x = 10
          def b(y: Int): Int = {
            x += 13        // scala 可以做此操作,对捕获的自由变量进行了修改,但是 python 不行,因为这个操作在python 内部是一个重新宣告x,重新赋值的操作,这会产生屏蔽效果,python 宣告变量 是“贴签”操作。所以,python貌似是不支持对捕获变量的修改。也就没有 所谓在函数内部进行修改,会影响 外部的自由变量的值 这种情况的出现。
            x + y
          }
          def c(z: Int): Int = {
            x + z
          }
          println(x) //10
          println(b(10)) //33  第一次捕获的自由变量的值是 x =10,所以此时的函数字面量中 x 绑定的是10
          println(x) //23 //在闭包内部对捕获的自由变量的修改,也会影响到外面的自由变量。
          println(c(3)) //26 自由变量经过 b() 的修改,c(3)再次捕获x时,x 已经是 23 了,此时的 函数字面量中绑定的x 是23
          0
        }
        println(a())
      }
    }
    

    python引用变量的顺序: 当前作用域局部变量->外层作用域变量->当前模块中的全局变量->python内置变量 。

  • 相关阅读:
    一个小时学会Git
    Git介绍,安装,Git+Git flow使用
    深度操作系统
    邮件模板定义
    每个程序员都应该知道的一些访问时延值
    C 盘的不速之客
    v14.0AspNetMicrosoft.Web.AspNet.Props 找不到
    WebAPI 2参数绑定方法
    VisualStudio 2015 开启IIS Express可以调试X64项目
    解决WINDOWS防火墙开启后Ping不通
  • 原文地址:https://www.cnblogs.com/jijizhazha/p/7446665.html
Copyright © 2020-2023  润新知