本文基于廖雪峰老师课程Python3写成,在学习过程当中会经常的发散性思维,力求把所有能考虑到的情况都考虑完全。(本文编辑器为Sublime Text3)
1、装饰器的用法和心得
a.下面为原代码:
def log(func):
def wrapper(*args,**kw):
print('call%s():'%func.__name__)
return func(*args,**kw)
return wrapper
@log
def now():
print('2018-2-22')
now()
得出结果:
callnow():
2018-2-22
[Finished in 0.2s]
b.下面逐步讨论上面这个代码:
def log(func):
def wrapper(*args,**kw):
print('call%s():'%func.__name__)
return func(*args,**kw)
return wrapper
@log
def now():
print('2018-2-22')
这看上去像一段返回函数,不过需要注意的有两点。
第一点:
括号里面的func参数到时候赋值进去的是一段新函数,@log下面的函数块
def now():
print('2018-2-22')
会产生一个一模一祥的函数块到func参数里面去,而不是它自己本身赋值进去。(@+需要调用的函数,@log函数代表调用log函数,(函数如果没有人调用它们则不会运行)下面必须还需要自己写一段函数作为赋值的参数)。
第二点:wrapper(*args,**kw)
wrapper()括号里面的*args,**kw前面的星号都是必要的,如果没有将会产生错误
TypeError: wrapper() missing 1 required positional argument: 'args'
而这两个星号的参数需要放在哪儿呢,及当@log下面的函数
def now():
print('2018-2-22')
=
(一个函数)
def wrapper(*args,**kw):#这里面的*args,*kw其实已经被'新'函数def now():
print('2018-2-22')赋值或者说替代掉了。
print('call%s():'%func.__name__)
return func(*args,**kw)
的时候,就需要在后边的函数参数里面写入*args,**kw(代表可以传入任何参数,廖雪峰老师说:now = log(now)。就是我把老师的公式给展开来)。还有一点需要注意:最后调用
now()
函数得到的不是print(‘2018-2-22’),而是
def wrapper(*args,**kw):
print('call%s():'%func.__name__)
return func(*args,**kw)
这个代码块的结果,也许这就是@的用法吧。。。
第三点:我们来讨论一下,一个星号和两个星号的区别(不局限于上面代码):
1、一个星号*的用法:
代表可以传入任何非关键字,显示出来的就会变成一个元组,看下面代码:
def prints(*arg):
print (arg);
print(prints (1,2,3,4,5,6,7))
打印的结果是一个元组: (1,2,3,4,5,6,7) , 也就是说该参数(arg) 将传进来的所有参数放在了一个元组中。
2、两个星号的用法
传入关键字,显示出来的就是一个dic,有key和value值。(所以在有两个星号的参数中我们需要传入两个参数作为一组,比如:a=1,b=2,c=3,d=4,e=5,f=6,g=7),代码如下:
def dics(**arg):
print (arg)
print(dics(a=1,b=2,c=3,d=4,e=5,f=6,g=7))
结果为:
{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6, 'g': 7}
课后作业:
import time,functools
def metric(fn):
@functools.wraps(fn)
def log(*args,**kw):
print('fn():%s'%time.ctime())(这里可以不用加)
print(fn(*args,**kw))
return log
@metric
def fast(x,y):
time.sleep(0.0012)
return x+y;
@metric
def slow(x,y,z):
time.sleep(0.1234)
return x*y*z;
f=fast(11,22)
s=slow(11,22,33)
if f !=33:
print('测试失败')
elif s!=7986:
print('测试失败')
结果为:
fn():Fri Feb 23 21:02:55 2018
33
fn():Fri Feb 23 21:02:55 2018
7986
测试失败
为什么不出现测试失败呢,因为我在代码中加入了这一行代码print('fn():%s'%time.ctime())
,结果会出现fn():Fri Feb 23 21:02:55 2018
所以会判断出错,把这一行代码去掉就可以了。