zoukankan      html  css  js  c++  java
  • 作用域、闭包、global、nonlocal

    1.作用域基础

    • python中一切与变量名有关的事件,都发生在赋值时,变量名在第一次赋值时才存在,同时要使用该变量必须先赋值。由于python中没有变量声明(如java、c#中),在变量赋值的区域就决定了该变量的命名空间。
    • 在函数(def声明)中声明的变量,只能在该函数内访问,并且要可以和函数外的变量声明相同,不会互相影响,但可以通过global或nonlocal中访问函数外的变量,但两个关键字的作用域和使用范围有差异。
    • 变量名解析原则:LEGB规则

          当在函数中使用未定义的变量名时,会从4个作用域中进行查找,首先是局部作用域(L)、如果有函数嵌套函数关系,那么内在函数会查找外部函数的作用域(E)、全局作用域中查找(G)、最后是内置的作用域,内置作用域指的是python中内部定义的一些关键字,在python3.X中保存在builtins模块中(B)。

    2.global

    • global语句告诉python函数计划生成一个或多个全局变量名-----简答来说就是将一个变量定义域全局作用域中,在函数内部可以访问该变量(函数中没有相同变量名),若要修改该变量要先在函数内用global关键字声明。
    • 在全局变量中,即使没用声明一个变量,但在函数中同样可以通过global关键字来指定一个变量为全局变量。
    x=99
    def f():
        x+=1  #会报错,相当于x=x+1,在该函数内没有首先对x赋值
        print(x)
    f()

    改进:

    x=99
    def f():
        global x #关键字
        x+=1 
        print(x) #100
    f()
    print(x) #100
    View Code
    y,z=1,2
    def f():
        global x #关键字
        x=y+z    #将x定义为全局变量,
        print(x) #3
    f()
    print(x) #3  函数外可以访问
    View Code

    3.闭包

    闭包存在于函数嵌套问题,其实,闭包指延伸了作用域的函数,其中包含函数定义体中的引用。

    def f1():
        x=4
        action=(lambda n: x**n) #匿名函数,外部函数调用后保存了x的值
        return action   #返回函数对象
    
    ac=f1()
    print(ac(3)) #64
    View Code

    在上述lambda中,x为自由变量,指未在本地作用域中绑定的变量,绑定在函数中的__closure__属性中,可以通过以下方法返回绑定值

    def f1():
        x=4
        action=(lambda n: x**n) #匿名函数,外部函数调用后保存了x的值
        return action   #返回函数对象
    
    ac=f1()
    print(ac(3)) #64
    print(ac.__code__.co_freevars)  #('x',)
    print(ac.__closure__[0].cell_contents)   # 4
    View Code

    闭包是一种函数,它会保留定义函数时存在的自由变量的绑定,这样调用函数时,虽然外部函数调用后其作用域不可用了,但仍可以使用那些绑定的值。

    4.nonlocal

    该声明和global关键字声明相似,但该关键字只能在函数嵌套函数中,并且声明该变量时外部函数必须要先定义该变量(与global不同,global可以先不在全局中定义该变量)。

    def tester(start):
        state=start
        def nested(label):
            nonlocal state   #用该关键字进行声明,其实有上面闭包可知,即使不声明也可以进行访问,但不能进行修改该值,同时在声明是外部函数作用域必须先定义该变量
            print(label,state)
            state+=1
        return nested
    
    n1=tester(1)
    n1('gtr')     #gtr 1
    n1('gtr111')  #gtr111 2
    
    n2=tester(10)
    n2('vfv')    #vfv 10
    n2('gtrg')   #gtrg 11
    #从中可以看到n1 n2对象传入的参数(1,10)独立互不影响,实质是每运行一次tester函数都会创建新的变量域
    View Code
  • 相关阅读:
    POJ 3140 Contestants Division (树dp)
    POJ 3107 Godfather (树重心)
    POJ 1655 Balancing Act (树的重心)
    HDU 3534 Tree (经典树形dp)
    HDU 1561 The more, The Better (树形dp)
    HDU 1011 Starship Troopers (树dp)
    Light oj 1085
    Light oj 1013
    Light oj 1134
    FZU 2224 An exciting GCD problem(GCD种类预处理+树状数组维护)同hdu5869
  • 原文地址:https://www.cnblogs.com/2019zjp/p/11868617.html
Copyright © 2011-2022 走看看