zoukankan      html  css  js  c++  java
  • 016.Python闭包函数以及locals和globals


    一 闭包函数

    内函数使用了外函数的局部变量,并且外函数把内函数返回出来的过程叫做闭包,这个内函数叫做闭包函数

    1.1 闭包函数语法

    def outer():
        a = 5
        def inner():
            print(a)
        return inner

    对比正常的局部变量

    局部变量的生命周期最短,在调用结束之后,立即释放.

    def func():
        a = 5
        print(a)
    func()
    print(a)

    执行

    1.2 闭包函数的定义

    复制代码
    def bibao():
            people = "孙仲谋"
            def caocao_say():
                    print("生子当如%s" % (people))
            return caocao_say
    
    func = bibao()
    # func = caocao_say
    func()
    复制代码

    执行

    [root@node10 python]# python3 test.py
    生子当如孙仲谋

    1.3 闭包函数的特点(升级)

    • 内函数使用了外函数的局部变量,外函数的局部变量与内函数发生绑定,延长该变量的生命周期(实际内存给它存储了这个值,暂时不释放)

    示例

    复制代码
    def grade(str1):
        def func_in(str2):
            print(str1+str2)
        return func_in
    
    a=grade('小李:')
    a('语文:118')
    
    b=grade('小红:')
    b('语文:109')
    b('数学:98')
    复制代码

    执行

    [root@node10 python]# python3 test.py
    小李:语文:118
    小红:语文:109
    小红:数学:98

    示例2

    复制代码
    def family():
            jiejie = "小红"
            meimei = "小明"
            money = 100
    
            def jiejie_hobby():
                    nonlocal money
                    money -=40
                    print("姐姐%s喜欢买零食,买了辣条钱还剩下%s" % (jiejie,money))
                    return money
    
            def meimei_hobby():
                    nonlocal money
                    money -= 30
                    print("妹妹%s喜欢买衣服,还剩下%s" % (meimei,money))
                    return money
    
            def big_manager():
                    return (jiejie_hobby,meimei_hobby)
    
            return big_manager
    
    func = family()
    # func = big_manager
    print(func,type(func))
    # func() = big_manager()
    tup = func()
    print(tup,type(tup))
    
    # 调用姐姐
    # jiejie = tup[0]
    # jiejie()
    
    res1 = tup[0]()
    print(res1)
    # 调用妹妹
    # meimei = tup[1]
    # meimei()
    
    res2 = tup[1]()
    print(res2)
    复制代码

    执行

    复制代码
    [root@node10 python]# python3 test.py
    <function family.<locals>.big_manager at 0x7fee9c4f21e0> <class 'function'>
    (<function family.<locals>.jiejie_hobby at 0x7fee9c4f20d0>, <function family.<locals>.meimei_hobby at 0x7fee9c4f2158>) <class 'tuple'>
    姐姐小红喜欢买零食,买了辣条钱还剩下60
    60
    妹妹小明喜欢买衣服,还剩下30
    30
    复制代码

     示例3

    复制代码
    def outer(val):
        def inner(num):
            return val + num
        return inner
        
    func = outer(10)
    # func = inner
    res = func(5)
    print(res)
    复制代码

    执行

    [root@node10 python]# python3 test.py
    15

    过程

    复制代码
        func = outer(10)
        val 形参接收到实参值10
        因为内函数使用了外函数的局部变量val,val与内函数发生绑定,延长val的生命周期
        res = func(5)
        num 形参接收到实参值5
        return 10 + 5 => return 15 返回到函数的调用处
        func(5) 是调用处 所以
        res = 15
    复制代码

    1.4 获取闭包函数使用的变量

    复制代码
    闭包函数.__closure__  返回单元cell  , cell 里面存的是对应的绑定变量
    res = func.__closure__  # 获取到一个元组
    res = res[0].cell_contents # res[0] 获取元组当中的第一个值 是一个cell单元 通过单元.cell_contents来获取其中的值,就会知道绑定的变量是谁了. cell_contents是一个属性
    print(res,type(res))
    # print(res.cell_content)
    # (<cell at 0x000001D6DAE17708: int object at 0x000000005EC26D30>,)
    复制代码

    示例

    复制代码
    def outer(val):
            def inner(num):
                    return val + num
            return inner
    
    func = outer(10)
    # func = inner
    res = func(5)
    print(res)
    print(func.__closure__)
    print(func.__closure__,type(func.__closure__))
    res = func.__closure__[0]
    print(res,type(res))
    
    res = func.__closure__[0].cell_contents
    print(res,type(res))
    复制代码

    执行

    复制代码
    [root@node10 python]# python3 test.py
    15
    (<cell at 0x7fe07763b7f8: int object at 0x7fe07750c7e0>,)
    (<cell at 0x7fe07763b7f8: int object at 0x7fe07750c7e0>,) <class 'tuple'>
    <cell at 0x7fe07763b7f8: int object at 0x7fe07750c7e0> <class 'cell'>
    10 <class 'int'>
    复制代码

    1.5 闭包的意义

    • 闭包可以优先使用外函数中的变量,并对闭包中的值起到了封装保护的作用.外部无法访问.

    模拟鼠标点击次数

    复制代码
    num = 0
    def click():
        global num
        num += 1
        return num
    res = click()
    res = click()
    res = click()
    # num = 100  恶意串改,我们获取的值就会出现错误
    res = click()
    res = click()
    print(res)
    复制代码

    使用闭包函数重写鼠标点击次数

    复制代码
    def click():
            x = 0
            def func():
                    nonlocal x
                    x+=1
                    return x
            return func
    
    click  = click()
    res = click()
    res = click()
    res = click()
    x = 100          #恶意修改,但是不影响结果
    res = click()
    res = click()
    print(res)
    复制代码

    执行

    [root@node10 python]# python3 test.py
    5

    二 locals 和 globals

    2.1 locals() 

    返回字典,获取当前作用域的所有内容

    • 如果在函数里:获取locals()调用之前,该作用域出现的内容
    • 如果在函数外:获取locals()打印返回值之前,该作用域出现的内容
    a = 1
    b = 2
    print(locals())

    执行

    复制代码
    [root@node10 python]# python3 test.py
    {'__name__': '__main__', 
    '__doc__': None, 如果在函数里:获取locals()调用之前,该作用域出现的内容     如果在函数外:获取locals()打印返回值之前,该作用域出现的内容 ', 
    '__package__': None,
    '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7ffa9ddb7208>,
    '__spec__': None, '__annotations__': {},
    '__builtins__': <module 'builtins' (built-in)>,
    '__file__': 'test.py',
    '__cached__': None,
    'a': 1,
    'b': 2,
    'func': <function func at 0x7ffa9de8ae18>, #全局中又这个函数,但是函数内部的局部变量不能获取
    'res': {...},
    'c': 3}
    复制代码

    所在作用域是局部命名空间,获取locals() 调用之前所出现的所有局部命名空间内容

    复制代码
    c=3
    d = 4
    def func():
        a = 1
        b = 2
        
        res = locals()
        c = 3
        print(res)
        
    f = 5
    func()
    复制代码

    执行

    [root@node10 python]# python3 test.py
    {'b': 2, 'a': 1}

    2.2 globals()

    返回字典,获取全局作用域的所有内容

    • 如果在函数里: 获取globals()调用之前,全局作用域出现的内容
    • 如果在函数外: 获取globals()打印返回值之前,全局作用域出现的内容

    globals在全局作用域中,只获取globals 打印返回值之前的所有全局空间的内容

    a = 1
    b = 2
    res = globals()
    print(res)
    c = 3

    执行

    复制代码
    [root@node10 python]# python3 test.py
    {'__name__': '__main__', 
    '__doc__': None,
    '__package__': None,
    '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7fcd746f5208>,
    '__spec__': None,
    '__annotations__': {},
    '__builtins__': <module 'builtins' (built-in)>,
    '__file__': 'test.py',
    '__cached__': None,
    'a': 1,
    'b': 2,
    'res': {...}}
    复制代码

    globals在局部作用域中,也仍然获取全局空间的所有内容,但是是在globals,打印返回值之前的所有.

    复制代码
    c = 13
    d = 14
    def func():
            a = 11
            b = 12
            res = globals()
            print(res)
    f = 19
    func()
    复制代码

    执行

    复制代码
    [root@node10 python]# python3 test.py
    {'__name__': '__main__', 
    '__doc__': None,
    '__package__': None,
    '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f16a5144208>,
    '__spec__': None,
    '__annotations__': {},
    '__builtins__': <module
    'builtins' (built-in)>,
    '__file__': 'test.py',
    '__cached__': None,
    'c': 13,
    'd': 14,
    'func': <function func at 0x7f16a5217e18>,
    'f': 19}
    复制代码

    只获取全局,没有ab的值

    动态创建全局变量 利用globals

    • globals 返回的是一个系统的全局字典,键是变量名,值是该标量所指向的值
    复制代码
    dic = globals()
    dic['hero'] = "风流倜傥,高大威猛,威武帅气,万人迷"
    print(hero)
    
    
    # 动态创建5个全局变量p1~p5
    def func():
            for i in range(1,6):
                    dic["p%d" % (i)] = i
    
    func()
    print(p1)
    print(p2)
    print(p3)
    print(p4)
    print(p5)
    复制代码

    执行

    复制代码
    [root@node10 python]# python3 test.py
    风流倜傥,高大威猛,威武帅气,万人迷
    1
    2
    3
    4
    5
    复制代码
    学习记录,小白一枚
  • 相关阅读:
    网页加速的14条优化法则 网站开发与优化
    .NET在后置代码中输入JS提示语句(背景不会变白)
    C语言变量声明内存分配
    SQL Server Hosting Toolkit
    An established connection was aborted by the software in your host machine
    C语言程序设计 2009春季考试时间和地点
    C语言程序设计 函数递归调用示例
    让.Net 程序脱离.net framework框架运行
    C语言程序设计 答疑安排(2009春季 110周) 有变动
    软件测试技术,软件项目管理 实验时间安排 2009春季
  • 原文地址:https://www.cnblogs.com/wangsirde0428/p/14322436.html
Copyright © 2011-2022 走看看