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