• python之函数作用域、嵌套以及闭包


    我们首先回忆一下Python代码运行的时候遇到函数是怎么做的,从Python解释器开始执行之后,就在内存中开辟里一个空间,每当遇到一个变量的时候,就把变量名和值之间对应的关系记录下来,但是当遇到函数定义的时候,解释器只是象征性的将函数名读如内存,表示知道这个函数存在了,至于函数内部的变量和逻辑,解释器根本不关心。

      等执行到函数调用的时候,Python解释器会再开辟一块内存来储存这个函数里面的内容,这个时候,才关注函数里面有哪些变量,而函数中的变量回储存在新开辟出来的内存中,函数中的变量只能在函数内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被清空。

    我们给这个‘存放名字与值的关系’的空间起了一个名字-------命名空间。

    代码在运行伊始,创建的存储“变量名与值的关系”的空间叫做全局命名空间;

    在函数的运行中开辟的临时的空间叫做局部命名空间。

    在python中,名称空间三种:

    • 全局名称空间
    • 局部名称空间(临时)
    • 内置名称空间




    作用域:

    • 全局作用域:作用于全局名称空间 内置名称空间
    • 局部作用域:作用于局部名称空间(临时)


    取值顺序:就近原则,单向从小到大范围
    局部名称空间 ---> 全局名称空间 ---> 内置名称空间


    加载顺序
    内置名称空间 ---> 全局名称空间(当程序执行时) ---> 局部名称空间(当函数调用的时候)

    局部名称空间 对全局名称空间的变量可以引用,但是不能改变。

    如果你在局部名称空间对一个变量进行修改,那么解释器会认为你的这个变量在局部中已经定义了。

    global

    • 1.在局部名称空间声明一个全局变量
    • 2.在局部名称空间可以对全局变量进行修改


    实际中
    不常用

    nonlocal

    • 相当于子函数对父函数的变量进行修改。
    • 此变量不能是全局变量
    • # 在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,
    • # 并且引用的哪层,从那层及以下此变量全部发生改变。
    # global
        # 1,在局部名称空间声明一个全局变量。
    # def func2():
    #     global name
    #     name = 'alex'
    # func2()
    # print(name)
    
        # 2,在局部名称空间可以对全局变量进行修改。
    # count = 1
    # def func1():
    #     global count
    #     count = count + 1
    #     print(count)
    # func1()
    # print(count)
    global
    # nonlocal
    # def func1():
    #     count = 666
    #     def func2():
    #         print(count)
    #     func2()
    # func1()
    nonlocal

    函数嵌套

    def func1():
        count = 666
        def inner():
            print(count)
            def func2():
                nonlocal count
                count += 1
                print('func2',count)
            func2()
            print('inner',count)
        inner()
        print('func1',count)
    func1()
    #  666  func2 667  inner 667  func1 667
    

      

    函数名的应用:

    • 1. 函数名就是函数的内存地址
    • 2. 函数名可以做为变量
    • 3. 函数名可以做为函数的参数
    • 4. 函数名可以当作函数的返回值
    • 5. 函数名可以做为容器类类型的元素


    像上面的函数名这种,叫第一类对象

    • 1. 可在运行期创建
    • 2. 可用作函数参数或返回值
    • 3. 可存入变量的实体。
     1. 函数名就是函数的内存地址
    # def func1():
    #     print(666)
    #
    # print(func1)  #<function func1 at 0x0000028BEC62C1E0>
    
    # 2. 函数名可以做为变量
    # f1 = func1
    # f1()
    
    
    # 3. 函数名可以做为函数的参数
    # def func1():
    #     print(666)
    #
    # def func2(x):
    #     x()  # func1()
    #
    # func2(func1)
    
    # 4. 函数名可以当作函数的返回值
    # def wraaper():
    #     def inner():
    #         print('----inner  ')
    #     return inner
    #
    # ret = wraaper()  # inner
    # ret()
    #
    # def func2():
    #     print('in the func2')
    #
    # def func3(x):
    #     print('in the func3') # x = func2
    #     return x
    #
    # f1 = func3(func2)  # func2
    # f1()
    
    # 5. 函数名可以做为容器类类型的元素
    # def func1():
    #     print('in func1')
    #
    # def func2():
    #     print('in func2')
    #
    # def func3():
    #     print('in func3')
    #
    # l1 = [func1, func2, func3, ]
    # for i in l1:
    #     i()
    
    # 像上面的函数名这种,叫第一类对象
    

      

    globals() 返回全局变量的一个字典
    locals() 返回当前位置的局部变量的字典

    # globals()  locals()
    
    # def func1():
    #     pass
    # print(globals())
    # print(locals())
    
    
    def func1():
        a = 2
        b = 3
        print(globals())
        print(locals())
    func1()
    

      

    闭包: 内层函数对外层函数的变量(非全局变量)的引用,并返回, 这样就形成了闭包。

    闭包的作用:
    当程序执行时,遇到了函数执行,他会在内存中开辟一个空间,局部名称空间。如果这个函数内部形成了闭包,
    那么他就不会随着函数的结束而立马消失。

    # def wrapper():
    #     name = 'alex'
    #     def inner():
    #         print(name)
    #     print(inner.__closure__)  # 判断是否闭包(<cell at 0x00000181FD0ED8E8: str object at 0x00000181FD00CE68>,)
    #                                     # 不是闭包返回None
    #     inner()
    #     return inner
    #
    # wrapper()
    
    name = 'alex'
    def wrapper(n):
        # 相当于 n = 'alex'
        def inner():
            print(n)
        print(inner.__closure__)  # 闭包
        inner()
        return inner
    
    wrapper(name)
    

      

  • 相关阅读:
    范畴定义
    泛函编程(0)-什么是泛函编程
    函数式语言的特性
    理解函数式编程
    未阅归档
    monad-本质解释- a monad is a design pattern--monad与泛型相关
    打印管理系统
    函数式JS: 原来promise是这样的monad
    Promise是Monad吗?
    Scala和范畴论 -- 对Monad的一点认识
  • 原文地址:https://www.cnblogs.com/eaoo/p/9488145.html
Copyright © 2020-2023  润新知