zoukankan      html  css  js  c++  java
  • day4----函数-闭包-装饰器

    本文档内容:

    1 python中三种名称空间和作用域

    2 函数的使用

    3 闭包

    4 装饰器

    一 python中三种名称空间和作用域

    1.1名称空间:

    当程序运行时,代码从上至下依次执行,它会将变量与值得关系存储在一个空间中,这个空间
    也叫命名空间。例如:name='xingchen'
    当程序遇到函数时,它会将函数名存在内存中,函数内部的变量和逻辑暂时不关心;
    当函数执行时,内存会临时开辟一个空间,存放函数体里面的代码(变量,代码等),这个空间叫临时名称空间
    也叫局部名称空间。
    函数外面访问不到临时空间的内容;随着函数的执行完毕,临时空间会释放掉。
    View Code

    python中名称空间分三种:
      内置名称空间
      全局名称空间
      局部名称空间
    作用域:
      全局作用域:
        内置名称空间
        全局名称空间
    局部作用域:
        局部名称空间
    加载顺序
    内置名称空间 ---》全局名称空间(程序执行时) ---》局部名称空间(函数执行时)
    取值顺序:单向不可逆
    局部名称空间 ---》全局名称空间 ----》内置名称空间

    1.2  globals和locals

    print(globals() ) 返回的是全局作用域里面的变量与其值,是一个字典

    print(locals())   返回的是当前的局部变量与其值,也是一个字典

    例如:

    def func1():
        a=1
        print(a)
        print(locals())
        print(globals())
    func1()
    View Code

    其结果为:

    1
    
    {'a': 1}
    
    {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000024FD014B240>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/PycharmProjects-x/s22day03/day4/lianxi.py', '__cached__': None, 'time': <module 'time' (built-in)>, 'func1': <function func1 at 0x0000024FD0056048>}
    View Code

    1.3 global和nonlocal

    global:声明一个全局变量,可以用作局部变量的关键字来修改或赋值给全局变量,

        但是:对可变数据类型(list,dict,set)可以直接引用不用通过global。如果默认参数是一个可变的数据类型,那么他在内存中永远是一个

    例如:下面的list就是可变数据类型,因此就不用global

    # def extendList(val,list=[]):
    #    list.append(val)
    #    return list
    # list1 = extendList(10)
    # print('list1=%s'%list1) # [10,]
    # list2 = extendList(123,[])
    # print('list2=%s'%list2) # [123,]
    # list3 = extendList('a')
    # print('list3=%s'%list3) #[10,'a']
    
    # print('list1=%s'%list1)
    # print('list2=%s'%list2)
    # print('list3=%s'%list3)
    
    其结果为:
    
    [10,a]
    
    [123]
    
    [10,a]
    View Code 

    nonlocal:在局部作用域中,对其父级作用域(或者更外层作用域)进行变量赋值或者修改,但是不能修改全局作用域

    例如:

    def func1():
        a=1
        def func2():
            b=10
            def func3():
                nonlocal a,b
                a=a+1
                b=b+1
                print(a,b)   #结果为 2,11
            func3()
            print(a,b)       #结果为 2,11,func2函数的b被引用了
        func2()
        print(a)        #结果为 2,这里的变量a被引用了,但是b不是在这里面引用的,所以打印b会报错
    func1()
    View Code

    二函数的使用

    函数名的本质就是函数的内存地址

    1 函数可以被引用

    例如:

    def func1():
        print('in func1')
    f=func1
    print(f)
    结果为:<function func1 at 0x000001E9313C6048>
    View Code

    2 函数可以作为容器类元素

    例如

    def func1():
        print('f1')
    
    def func2():
        print('f2')
        
    l1=[func1,func2]
    l2={'f1':func1,'f2':func2}
    
    l1[0]()
    l2['f2']()
    View Code

    3 函数可以作为返回值

    def f1():
        print('f1')
    
    def func1(argv):
        argv()
        return argv
    
    f = func1(f1)
    f()
    View Code

    其他: 第一类对象

    第一类对象(first-class object)指
    1.可在运行期创建
    2.可用作函数参数或返回值
    3.可存入变量的实体。
    View Code

     三 闭包

    内部函数包含对外部作用域而非全局作用域变量的引用,该内部函数称为闭包函数,一般用于装饰器或者网络爬取内容

    判断闭包函数的方法__closure__

    例如:

    def func():
        name = 'eva'
        def inner():
            print(name)
         print(inner.__closure__) #结果中函数含有cell元素,否则为none
    return inner 
    f = func() 
    f()
    View Code

    闭包函数一个例子

        def line_conf(a, b):
            def line(x):
                return a * x + b
            return line

    四 装饰器

     装饰器的本质是一个python函数,基于闭包函数,让其他的函数在不改变源码和调用方式的前提下,增加新的功能

       装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景。

    下面看看装饰器的形成过程:

    原始的代码

    import time
    # print(time.time()) # 1527326532.2688255
    
    # def func1():
    #   time.sleep(0.3)
    #    print('非常复杂......')
    #
    # start_time = time.time()
    # func1()
    # end_time = time.time()
    # print('此函数的执行效率%s' %(end_time-start_time))
    View Code

    # 改版1:我要封装到一个函数中

    # def func1():
    #    time.sleep(0.3)
    #    print('非常复杂......')
    #
    # def func2():
    #    time.sleep(0.3)
    #    print('特别复杂......')
    #
    # func1()
    # func2()
    View Code

    # # 改版2:被测试函数当参数传入,可以测试多个函数的执行效率

    # def timmer(f):
    #    start_time = time.time()
    #   f()
    #    end_time = time.time()
    #    print('此函数的执行效率%s' %(end_time-start_time))
    #
    # timmer(func1)
    # timmer(func2)
    View Code

    # 改版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)
    View Code

    # 改版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()
    View Code

    # 改版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()
    View Code

    # 改版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()
    View Code

    # 改版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)
    View Code
    至此装饰器的固定结构如下
    def timer(func):
        def inner(*args,**kwargs):
            '''执行函数之前要做的'''
            re = func(*args,**kwargs)
            '''执行函数之后要做的'''
            return re
        return inner
    View Code

     但是如何函数有很多,如何取消他们呢,以后如果又加上呢---带参数的装饰器模型

    def outer(flag):
        def timer(func):
            def inner(*args,**kwargs):
                if flag:
                    print('''执行函数之前要做的''')
                re = func(*args,**kwargs)
                if flag:
                    print('''执行函数之后要做的''')
                return re
            return inner
        return timer
    
    @outer(False)  #改为false是不执行装饰器内的内容
    def func():
        print(111)
    
    func()
    View Code

    如果多个装饰器装饰一个函数呢

    def wrapper1(func):
        def inner():
            print('wrapper1 ,before func')
            func()
            print('wrapper1 ,after func')
        return inner
    
    def wrapper2(func):
        def inner():
            print('wrapper2 ,before func')
            func()
            print('wrapper2 ,after func')
        return inner
    
    
    @wrapper1
    @wrapper2
    def f():
        print('in f')
    f()
    View Code

    其结果为:

    wrapper1 ,before func
    wrapper2 ,before func
    in f
    wrapper2 ,after func
    wrapper1 ,after func
    View Code

     装饰器的另外一种方法:

    import functools
    def wrapper(func):
        @functools.wraps(func)
        def inner(*args, **kwargs):
            print('我是装饰器')
            return func(*args,**kwargs)
        print('--------')
        return inner
    
    @wrapper
    def index():
        print('我是被装饰函数')
        return None

    index()

    ---------------------------------------------------------------------------------回顶部----------------------------------------------------------------------------------------------------------------------------

  • 相关阅读:
    软件需求分析阅读笔记1
    在Ubuntu上搭建Zookeeper集群
    第三周学习进度总结
    读书计划
    假期周进度报告3
    热词分析及解释
    假期周进度报告(二)
    假期周进度报告(一)
    PHP商城
    第十六周总结
  • 原文地址:https://www.cnblogs.com/mmyy-blog/p/9109425.html
Copyright © 2011-2022 走看看