• python入门(十五):装饰器


    1、装饰器(decorator):设计模式

    作用:给不同的函数和方法,增加不同的公用的功能。

    @classmethod,@staticmethod等均是装饰器

    定义一个装饰函数,函数必须返回一个闭包函数,并且func(被装饰的函数)会被python自动传递给装饰函数,作为装饰函数的一个参数

    2、闭包

    函数对象+函数内部需要使用的一个外部变量=函数返回的整体

    闭包必须返回函数

    装饰函数中的闭包函数结构如下:

    def wrapper(*arg,**kw):

      xxxx干一些事情

      func(*arg,**kw)

      yyyy干另外一些事情

    return wrapper

        1)函数对象与调用函数

    >>> sum

    <built-in function sum>                #sum是一个内置的函数,不加()是函数对象

                                         #函数对象指的是指向函数所在的内存地址

    >>> sum([1,2,3,4])                     #加了括号并且有传参,就是函数调用

    10

    >>> def pri():

    ...     return sum                     #函数执行后返回了另外一个函数对象

    ...

    >>> pri()

    <built-in function sum>

    >>> def func1(func):

    ...     return func([1,2,3,4])             #函数的参数可以使用函数对象

    ...                                   #函数对象sum会传给func等价于sum([1,2,3,4])

    >>> print(func1(sum))                

    10

    >>> def func1(func):

    ...     return func([1,2,3,4])

    ...

    >>> func1(sum)

    10

    >>> 

    >>> def add(l):                        #l就是返回的[1,2,3,4]

    ...     result = 0

    ...     for i in l:

    ...         result+=i

    ...     return result

    ...

    >>> func1(add)                       #add函数对象作为一个参数,不用加()

    10

        2) 闭包模型

    def func():                           #定义了函数func()

        x = 100                         #定义了一个变量

        def func1():                      #在函数func()中又定义了一个函数func1()

           print(x)                       #print(x)语句可以访问到x=100变量

        return func1                     #func()这个函数返回func1

    >>> func()                           #调用func()函数,并未调用到func1,所以返回了

    <function func.<locals>.func1 at 0x000001B478F5EE18>#func1的函数对象

    >>> a=func()                        #将函数对象赋值给a

    >>> a                              #再次打印a时,依然返回函数的内存地址

    <function func.<locals>.func1 at 0x000001B478F5EF28>

    >>> func()()                         #函数内部调用函数,需要写两个()

    100                                 #有调用到func1(),所以会返回100

    >>> def func():

    ...     x = 100

    ...     def func1():

    ...        print(x)

    ...     return func1()               #return的是func1(),函数的调用,所以会进行打印

    ...

    >>> func()

    100

    >>> a = func()                     #将func()的结果赋值给a

    100

    >>> a                            #查看a的值返回为空

    >>> type(a)                       #a的类型是None,因为100是在func1里的print(x)

    <class 'NoneType'>                #打印输出的,但是func1这个函数没有return,默认返回none,func这个函数的返回值是func(),none,所以a的值也是None

    闭包部分:

    def func():

        x = 100                       #黑体部分是闭包

        def func1():

           print(x)

           return None

        return func1

    a=func()                          #闭包部分赋值给了a

    函数对象+函数内部需要使用的一个外部变量=函数返回的整体

    简易版:函数+需要的外部变量,一起返回了

    3、查看闭包变量

    >>> def func():

    ...      x = 100

    ...      def func1():

    ...         print(x)

    ...         return None

    ...      return func1

    ...

    >>> a=func()        #a等价于func1()的内存地址+x=100,作为一个闭包,赋值给了a

    >>> a.__closure__

    (<cell at 0x000001B478EC8828: int object at 0x000000006FF17760>,)

    #int代表闭包里面的变量,int作为闭包变量的一部分返回了

    4、闭包的模型:计算一下不同函数的执行时间

    1) 一般方法

    >>> import time

    >>> def a():                             #函数a()的执行时间

    ...     time1= time.time()

    ...     i = 1

    ...     while i<10000000:

    ...         i+=1

    ...     time2=time.time()

    ...     print("time elapsed:%s"%(time2-time1))

    ...

    >>> 

    >>> def b():                            #函数b()的执行时间

    ...     time1= time.time()

    ...     i = 1

    ...     while i<90000000:

    ...         i+=1

    ...     time2=time.time()

    ...     print("time elapsed:%s"%(time2-time1))

    ...

    >>> a()

    time elapsed:0.5356054306030273

    >>> b()

    time elapsed:4.651560068130493

    问:如果是统计100个函数运行的时间,是否代码要重复多次?

    2) 通过函数来解决:

    >>> def timer(func):           #函数本身作为参数

    ...     time1= time.time()

    ...     func()                 #传到函数里面做了一次调用

    ...     time2=time.time()

    ...     print("time elapsed:%s"%(time2-time1))

    ...

    >>> 

    >>> 

    >>> import time

    >>> def a():

    ...     i = 1

    ...     while i<10000000:

    ...         i+=1

    ...

    >>> def b():

    ...     i = 1

    ...     while i<90000000:

    ...         i+=1

    ...

    >>> timer(a)

    time elapsed:0.5086383819580078

    >>> timer(b)

    time elapsed:4.571778774261475

    3) 通过装饰器来解决;

    import time

    def timer(func):                 #装饰函数,装饰器对应的函数必须是闭包函数!!!

        def func1():  

            time1= time.time()

            func()

            time2=time.time()

            print("time elapsed:%s"%(time2-time1))   

        return func1

    #闭包是:func(闭包变量)+func1(闭包函数)

    @timer

    def a():

        i = 1

        while i<10000000:

            i+=1

    @timer

    def b():

        i = 1

        while i<90000000:

            i+=1

    a()           #a等价于timer(a),由python编译器自动完成的,a()等价于timer(a)()

    b()           #b等价于timer(b),由python编译器自动完成的,b()等价于timer(b)()

    4) 定义了装饰函数后,调用时也可不用装饰器

    import time

    def timer(func):                  #定义了装饰函数

        def func1():  

            time1= time.time()       #定义函数调用前做的事儿

            func()

            time2=time.time()        #定义函数调用后干的事儿

            print("time elapsed:%s"%(time2-time1))   

        return func1

    @timer

    def a():                   #函数a()使用了装饰器

        i = 1

        while i<10000000:

            i+=1

    def b():                  #函数b()未使用装饰函数

        i = 1

        while i<90000000:

            i+=1

        print("!")            #仅为了证明函数b被调用

    a()                     #a==timer(a),timer(a)(),会调用到func1()

    timer(b())               #该方法写的有误,如果想要调用到func1(),()要在外写

    b()                   #当有装饰函数,但是没有装饰器时,单独写,无法完成共同的功能,

    timer(b)()               #仅仅是对当前函数做了一次调用

    运行结果;

    E:>python a.py

    time elapsed:1.4122233390808105

    !

    time elapsed:4.318440914154053

     5、作为参数的函数有参数

    1) 所有的函数,参数数量都是一样的

    import time

    def timer(func):

        def func1(arg):  

            time1= time.time()

            func(arg)

            time2=time.time()

            print("time elapsed:%s"%(time2-time1))   

        return func1

    @timer

    def a(count):

        print("执行次数:",count)

        i = 1

        while i<count:

            i+=1

        print("a is over!")

    a(20)                  #调用时传的参数等价于func1(arg)中的arg,即20—arg

    运行结果:

    E:>python a.py

    执行次数: 20

    a is over!

    time elapsed:0.000997781753540039

    2)所有的函数,调用的参数的数量并不是一致的

    import time

    def timer(func):

        def func1(*arg):              #此处的参数需要根据不同的函数动态变化即可变参数

            time1= time.time()

            func(*arg)               #可变参数可解决问题

            time2=time.time()

            print("time elapsed:%s"%(time2-time1))   

        return func1

    @timer

    def a(count):                    #函数a只有一个参数

        print("执行次数:",count)

        i = 1

        while i<count:

            i+=1

        print("a is over!")

    @timer

    def b(count1,count2):              #函数b有两个参数

        print("执行次数:",count1+count2)

    a(20)                          

    b(1,2)

    运行结果;

    E:>python a.py

    执行次数: 20

    a is over!

    time elapsed:0.00196075439453125

    执行次数: 3

    time elapsed:0.0009877681732177734

    3) 传参时,有赋值

    import time

    def timer(func):

        def func1(*arg,**kw):        #**kw可将count==100传入

            time1= time.time()

            func(*arg,**kw)

            time2=time.time()

            print("time elapsed:%s"%(time2-time1))   

        return func1

    @timer

    def a(count):

        print("执行次数:",count)

        i = 1

        while i<count:

            i+=1

        print("a is over!")

    @timer

    def b(count1,count2,count3):

        print("执行次数:",count1+count2+count3)

    a(20)

    b(1,2,count3=100)          #调用函数传参时,有赋值,*arg便不能生效,需要**kw解决

    运行结果:

    E:>python a.py

    执行次数: 20

    a is over!

    time elapsed:0.001954793930053711

    执行次数: 103

    time elapsed:0.0

  • 相关阅读:
    Socket通信的理解
    wpf listbox 内的内容显示问题,需要设置里面的itemsPresenter
    C#的两个大方向
    QT的安装和配置及helloqt程序的编写时遇到的问题
    华为交换机基础命令
    华为创建VLAN及VLAN间通讯
    powershell查询AD域账号详细信息
    Powershell从EXCEL导入大量用户
    映射网络驱动器
    域策略更新及导出
  • 原文地址:https://www.cnblogs.com/suitcases/p/10756599.html
Copyright © 2020-2023  润新知