• python之函数的进阶、闭包、装饰器(4)


    本节内容:函数的进阶、闭包、装饰器

      1.名称空间

      2.作用域

      3.取值顺序

      4.函数的嵌套

      5.内置函数

      6.关键字

           7.函数的应用

           8.闭包

           9.装饰器

    1、名称空间                                                                                                   

    1.1 名称空间

    当程序运行时,代码从上之下一次执行,他会将变量与值的关系存储在一个空间中,这个空间叫做名称空间,命名空间,全局名称空间。

    1.2 局部名称空间

    当程序遇到函数时,他会将函数名存在内存中,函数体莫不关心。

    当函数执行时,内存会临时开辟一个空间,存放函数体里面的代码(变量,代码等),

    函数外面访问不到临时空间的内容,随着函数的执行完毕,临时名称空间会释放掉,

    向这个临时开辟的空间叫临时名称空间,也叫局部名称空间。

      

    1.3 Python中名称空间种类

        内置名称空间。

        全局名称空间。

        局部名称空间。

    2、作用域                                                                                                       

    2.1 全局作用域

        内置名称空间

        全局名称空间

    2.2 局部作用域

        局部名称空间

    2.3 加载顺序

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

    3、取值顺序                                                                                                  

    取值顺序:单向不可逆

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

    3.1 先从局部找

    name1 = 'oldboy'
    def func2():
        name1 = 'alex'
        print(name1)
    func2()
    =====>输出
    alex
    View Code

    3.2 再从全局找

    name1 = 'oldboy'
    def func2():
        print(name1)
    func2()
    =====>输出
    oldboy
    View Code

    3.3 最后从内置空间找

    def func2():
        print(input)
    func2()
    =====>输出
    <build-in function input>
    View Code
    4、函数的嵌套                                                        
    def func1():
        print(666)
    
    def func2():
        func1()
        print(333)
    
    def func3():
        func2()
        print(222)
    print(111)
    func3()
    print(555)
    =====>输出
    111
    666
    333
    222
    555
    ==========
    def func1():
        name = 'alex'
        print(name)
        def func2():
            name1 = '太白'
            print(333)
        print(444)
        func2()
    func1()
    =====>输出
    alex
    444
    333
    View Code

    5、内置函数                                                                                                

    5.1 globals()

    返回一个字典,字典里面的内容是全局作用域的内容。

    name = 'alex'
    age = 1000
    sex = ''
    def func1():
        name1 = 'oldboy'
        age = 10000
    func1()
    print(globals())
    print(locals())
    =========>输出
    None, 'name': 'alex', 'age': 1000, 'sex': '', 'func1': <function func1 at 0x0000000001CF2E18>}
    None, 'name': 'alex', 'age': 1000, 'sex': '', 'func1': <function func1 at 0x0000000001CF2E18>}
    View Code

    5.2 locals()

    返回一个字典,当前位置 的所有变量。

    def func1():
        name1 = 'oldboy'
        age = 10000
        def func2():
            name2 = 'wusir'
            age2 = 25
            print(globals())
            print(locals())
        func2()
    func1()
    =====>输出
    None, 'func1': <function func1 at 0x0000000001D02E18>}
    {'age2': 25, 'name2': 'wusir'}
    View Code

    6、关键字                                                                                                  

    6.1 global

    6.1.1 引用并改变一个全局变量

    count = 1
    def func1():
        global count
        count = count + 1
        # count = count + 100
        print(count)
    func1()
    print(count)
    =====>输出
    2
    2
    View Code

    6.1.2 在局部作用域声明一个全局变量

    def func1():
        global name
        name = 'alex'
        print(name)
    func1()
    print(name)
    =====>输出
    alex
    alex
    View Code

    6.2 nonlocal

    1、不能操作全局变量

    从哪层引用的该变量,从那层开始全部改变。

    def func1():
        count = 1
        def inner():
            nonlocal count
            count = count + 3
            print(count)
            def inner2():
               pass
        inner()
        print(count)
    func1()
    =====>输出
    4
    4
    View Code
    取值:引用而不是改变
    取值是从小到大取值 LEGB
    想改变上层空间的变量 要用到global nonlocal
    2、对于可变的数据类型 list dict set 不用global nonlocal
    list = []
    def func1():
        list.append(666)
    func1()
    print(list)
    =====>输出
    [666]
    View Code

    3、如果默认参数是一个可变的数据类型,那么他在内存中永远是一个

    def extendList(val,list=[]):
        list.append(val)
        return list
    list1 = extendList(10)
    print('list1=%s'%list1)  
    list2 = extendList(123,[])
    print('list2=%s'%list2)
    list3 = extendList('a')
    print('list3=%s'%list3) 
    
    print('list1=%s'%list1)
    print('list2=%s'%list2)
    print('list3=%s'%list3)
    =======>输出
    list1=[10]
    list2=[123]
    list3=[10, 'a']
    list1=[10, 'a']
    list2=[123]
    list3=[10, 'a']
    View Code

    7、函数名的应用                                                     

    def func1():
        print(666)
    1 打印函数名
    print(func1)  # <function func1 at 0x000000000258F9D8>
    
    2 函数名可以作为容器类数据的元素
    def func1():
        print(111)
    
    def func2():
        print(222)
    
    def func3():
        print(333)
    
    l1 = [func1, func2, func3]
    for i in l1:
        i()
    
    3 函数名可以作为函数的参数
    
    def func1():
        print(111)
    
    def func2(x):
        print(x)
        x()
        print(222)
    
    func2(func1)
    
    4 函数名可以作为函数的返回值
    
    def func1():
        return 111
    
    def func2(x):  # x = func1
        print(222)
        return x
    
    ret = func2(func1)  # func1
    print(ret())
    print(ret)
    View Code

    7.1 第一类对象

    def func3(x):
        print(x)
        return x
    
    def func1():
        print(1111)
        return 111
    f1 = func1
    f2 = f1
    f3 = f2
    print(f3)
    f3()
    =========>输出
    <function func1 at 0x00000000025120D0>
    1111
    View Code

    8、闭包                                                                                                       

    内层函数对外层函数非全局变量的引用,就叫做闭包。

    def wrapper():
        name = 'alex'
        def inner():
            print(name)
        inner()
    wrapper()
    ======>输出
    alex
    =======
    name = 'alex'
    def wrapper():
        def inner():
            print(name)
        inner()
        print(inner.__closure__)  # None
    wrapper()
    =======>输出
    alex
    None
    View Code

    8.1 通过函数名.__closure__

    name = 'alex'
    def wrapper(x):
        x = name
        def inner():
            print(x)
        inner()
        print(inner.__closure__) 
    wrapper(name)
    =====>输出
    alex
    (<cell at 0x0000000001E16498: str object at 0x000000000049C110>,)
    View Code
    如果 python 解释器遇到了闭包,他有一个机制,这个闭包不会随着函数的结束而释放。
    9、装饰器                                                                                                   
    import time
    print(time.time()) 
    
    def func1():
        time.sleep(0.3)
        print('非常复杂......')
    
    start_time = time.time()
    func1()
    end_time = time.time()
    print('此函数的执行效率%s' %(end_time-start_time))
    ===========>输出
    1527471870.8405445
    非常复杂......
    此函数的执行效率0.3000171184539795
    ==============
    # 改版1:我要封装到一个函数中
    import time
    print(time.time()) 
    def func1():
        time.sleep(0.3)
        print('非常复杂......')
    
    def func2():
        time.sleep(0.3)
        print('特别复杂......')
    
    func1()
    func2()
    ========>输出
    1527471978.33138
    非常复杂......
    特别复杂......
    ==============
    # 改版2:被测试函数当参数传入,可以测试多个函数的执行效率
    def timmer(f):
        start_time = time.time()
        f()
        end_time = time.time()
        print('此函数的执行效率%s' %(end_time-start_time))
    
    timmer(func1)
    timmer(func2)
    =================
    改版3::测试函数执行效率的同时,不要改变原函数的调用方式。
    def func1():
        time.sleep(0.3)
        print('非常复杂......')
    def func2():
        time.sleep(0.3)
        print('特别复杂......')
    # func1()
    # func2()
    def timmer(f):
        start_time = time.time()
        f()
        end_time = time.time()
        print('此函数的执行效率%s' % (end_time - start_time))
    f1 = func1
    func1 = timmer  #
    func1(f1)  # timmer(func1)
    =================
    改版4::改版3虽然大体上满足了我的要求,但是增加两行代码,
    而且多了参数,不好,继续改,尽量不添加其他代码,而且做到调用时一模一样
    最简单的装饰器。
    def func1():
        time.sleep(0.3)
        print('非常复杂......')
    def func2():
        time.sleep(0.3)
        print('特别复杂......')
    # func1()
    # func2()
    
    def timmer(f):  # f = func1 函数名
        def inner():
            start_time = time.time()
            f()
            end_time = time.time()
            print('此函数的执行效率%s' % (end_time - start_time))
        return inner
    
    func1 = timmer(func1)  # inner
    func2 = timmer(func2)  # inner
    func1()  # inner()
    func2()
    
    ========================
    改版5::改版4每次测试一个函数的执行效率时,都需要加一行 func1 = timmer(func1)代码,麻烦
    python提出了一个语法糖 @。
    
    
    def timmer(f):  # f = func1 函数名
        def inner():
            start_time = time.time()
            f()
            end_time = time.time()
            print('此函数的执行效率%s' % (end_time - start_time))
        return inner
    
    @timmer  # func1 = timmer(func1)  inner
    def func1():
        time.sleep(0.3)
        print('非常复杂......')
    
    func1()  # inner()
    ========================
    改版6:被装饰的函数肯定要有参数的,你现在不能满足,解决这个问题。
    被装饰的函数带参数的装饰器
    def timmer(f):  # f = func1 函数名
        def inner(*args,**kwargs):  # args = (1,2),kwargs {sex:'nv',name:'alex'}
            start_time = time.time()
            f(*args,**kwargs)  # f(1,2,,sex='nv',name='alex')
            end_time = time.time()
            print('此函数的执行效率%s' % (end_time - start_time))
        return inner
    
    @timmer  # func1 = timmer(func1)  inner
    def func1(a,b):
        time.sleep(0.3)
        print(a,b)
        print('非常复杂......')
    
    
    @timmer  # func1 = timmer(func1)  inner
    def func2(a,b,name,sex='man'):  # f(1,2,,sex='nv',name='alex')
        time.sleep(0.3)
        print(a,b,sex,name)
        print('非常复杂......')
    
    func2(1,2,sex='nv',name='alex')  # inner()
    ====================
    改版7:被装饰的函数肯定要有返回值的,解决这个问题。
    被装饰的函数带参数且有返回值的装饰器
    
    def timmer(f):  # f = func2 函数名
        def inner(*args,**kwargs):  # args = (1,2),kwargs {sex:'nv',name:'alex'}
            start_time = time.time()
            ret = f(*args,**kwargs)  # f(1,2,,sex='nv',name='alex')
            end_time = time.time()
            print('此函数的执行效率%s' % (end_time - start_time))
            return ret
        return inner
    @timmer  # func1 = timmer(func1)  inner
    def func2(a,b,name,sex='man'):  # f(1,2,,sex='nv',name='alex')
        time.sleep(0.3)
        print(a,b,sex,name)
        print('非常复杂......')
        return 666
    
    print(func2(1,2,sex='nv',name='alex'))  # inner()
    
    def timmer(f):
        def inner(*args,**kwargs):
            start_time = time.time()
            ret = f(*args,**kwargs)
            end_time = time.time()
            print('此函数的执行效率%s' % (end_time - start_time))
            return ret
        return inner
    @timmer
    def func2(a,b,name,sex='man'):
        time.sleep(0.3)
        print(a,b,sex,name)
        print('非常复杂......')
        return 666
    
    ret1 = func2(1,2,sex='nv',name='alex')
    print(ret1)
    
    
    def wrapper(f):
        def inner(*args,**kwargs):
            """被装饰函数执行之前的操作"""
    
            ret = f(*args,**kwargs)
            """被装饰函数执行之后的操作"""
            return ret
        return inner
    View Code
    装饰器 本质就是闭包
    装饰器根本作用:在不影响原函数执行的基础上,增加一些额外的功能登录认证,打印日志等等。
  • 相关阅读:
    什么是Portal!
    Maven 让事情变得简单
    HTTP协议详解
    函数实现不放在头文件的原因,及何时可以放头文件的情况
    Linux中的内存管理(四)Heap
    寿星万年历Lua实现
    TCP epoll触发后只accept一次带来的问题
    生产者消费者问题
    Windows SDK 实现不规则窗口
    论迭代式的产品开发方法
  • 原文地址:https://www.cnblogs.com/bowen-li/p/s187010.html
Copyright © 2020-2023  润新知