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

原文地址:https://www.cnblogs.com/suitcases/p/10756599.html