装饰器
1.闭包
def fun():
def wrapper(x,y):
return x+y
return wrapper
g=fun()
print g
print g(1,2)
执行结果:python首先读取def fun()发现是函数,直接跳到g=fun(),再到下一条命令,print g,返回到def fun(),读取def wrapper(),return返回 wrapper,所以g为函数
,完后后打印g(1,2),返回x+y也就是3。这就是闭包
<function wrapper at 0x7fd37bda19b0>
3
2.装饰器:器,函数;实质上是用来装饰函数的函数; 接收其他函数作为参数;对于原有的函数做了新的修改;
def addinfo(fun):
def wrapper():
print '新年快乐'
fun() ##这个函数就是transferMoney()
print 'fun函数名是%s' %(fun.__name__)
return wrapper
@addinfo ###python的语法糖
def transferMoney():
print '欢迎使用ICBC atm 取款系统'
transferMoney()
运行结果
新年快乐
欢迎使用ICBC atm 取款系统
fun函数名是transferMoney
3.计时器,需要加载time模块
import time
def timmer(function):
def wrapper(*args,**kwargs):
"""this is wrapper"""
start_time = time.time()
function(*args,**kwargs)
end_time = time.time()
print "%s running time is %s" %(function.__name__,end_time - start_time)
return wrapper
@timmer
def login(name,passwd):
if name == 'root' and passwd == 'redhat':
print 'login ok'
else:
print 'login fail'
login('root','redhat')
print login.__name__
print login.__doc__
运行结果
login ok
login running time is 1.69277191162e-05
wrapper
this is wrapper
4.functools.wraps(fun)可以保留函数原有的函数名和函数帮助文档;
import time
import functools
def timmer(function):
@functools.wraps(function)
def wrapper(*args,**kwargs):
"""this is wrapper"""
start_time = time.time()
function(*args,**kwargs)
end_time = time.time()
print "%s running time is %s" %(function.__name__,end_time - start_time)
return wrapper
@timmer
def login(name,passwd):
if name == 'root' and passwd == 'redhat':
print 'login ok'
else:
print 'login fail'
login('root','redhat')
print login.__name__
print login.__doc__
运行结果:函数说明信息为none,login函数的说明信息写在login下才会实现
login ok
login running time is 2.00271606445e-05
login
None
login函数的说明信息写在login下才会实现
import functools
def timmer(function):
@functools.wraps(function)
def wrapper(*args,**kwargs):
"""this is wrapper"""
start_time = time.time()
function(*args,**kwargs)
end_time = time.time()
print "%s running time is %s" %(function.__name__,end_time - start_time)
return wrapper
@timmer
def login(name,passwd):
"""这是login函数的说明信息"""
if name == 'root' and passwd == 'redhat':
print 'login ok'
else:
print 'login fail'
login('root','redhat')
print login.__name__
print login.__doc__
结果:
login ok
login running time is 2.19345092773e-05
login
这是login函数的说明信息
5.装饰器传参,inspect:不管是默认参数, 必选参数, 可变参数, 关键子参数, 都会将形式参数和传的值封装为字典;便于使用;
import inspect
def is_root(f):
def wrapper(*args,**kwargs):
d = inspect.getcallargs(f, *args, **kwargs)
print 'f_args:%s' %d
if d.get('name') == 'root':
f(*args,**kwargs)
else:
raise Exception('不是root用户')
return wrapper
@is_root
def transferMoney(name):
print '转账....'
transferMoney('root')
运行结果:
f_args:{'name': 'root'}
转账....
换个用户比如student
import inspect
def is_root(f):
def wrapper(*args,**kwargs):
d = inspect.getcallargs(f, *args, **kwargs)
print 'f_args:%s' %d
if d.get('name') == 'root':
f(*args,**kwargs)
else:
raise Exception('不是root用户')
return wrapper
@is_root
def transferMoney(name):
print '转账....'
transferMoney('student')
-------
结果:
f_args:{'name': 'student'}
Traceback (most recent call last):
File "/Python/root/day-06/06_1.py", line 70, in <module>
transferMoney('student')
File "/Python/root/day-06/06_1.py", line 63, in wrapper
raise Exception('不是root用户')
Exception: 不是root用户
6.装饰器传多个类型参数
import inspect
def datatype(*args_type):
def require_num(f):
def wrapper(*args,**kwargs):
for i in args + tuple(kwargs.values()):
print args_type ##1和2+2j各遍历一次所以打印两次
if not isinstance(i,args_type):
raise TypeError('[参数错误]:%s only accept num as argument.' %f.__name__)
return f(*args,**kwargs)
return wrapper
return require_num
@datatype(int,float,complex) ##在这控制参数类型
def add(x,y):
return x+y
print add(1,2+2j)
运行结果
(<type 'int'>, <type 'float'>, <type 'complex'>)
(<type 'int'>, <type 'float'>, <type 'complex'>)
(3+2j)
7.多个装饰器:
python首先到两个定义的函数不操作,接着到@makebold,不操作,到@makeitalic返回def makeitalic(f):读取def wrapper():返回 return wrapper,再到def makebold(f):读取def wrapper():返回第一个函数的wrapper;跳到最后print html()发现是个函数回到第一个函数def wrapper():执行return “” + f() + ““,再返回第二个def makebold(f):执行 “” + f() + ““,之后到@makebold,再跳到html函数执行 return “hello python”完成
def makebold(f):
def wrapper():
return "<b>" + f() + "</b>"
return wrapper
def makeitalic(f):
def wrapper():
return "<i>" + f() + "</i>"
return wrapper
@makebold ###后执行
@makeitalic ###先执行
def html():
return "hello python"
print html()
结果:
“<b><i>hello python</i></b>“ ##markdown 语法有点和html相像,防止被转化,两边加了引号
8.函数调用次数的统计
def counter(f):
def wrapper(*args,**kwargs):
wrapper.count+=1
f(*args,**kwargs)
print "%s has been used %s" %(f.__name__,wrapper.count)
wrapper.count = 0
return wrapper
@counter
def fun():
print "hello python"
f1=fun()
f2=fun()
f3=fun()
结果:
hello python
fun has been used 1
hello python
fun has been used 2
hello python
fun has been used 3
装饰器小结
1.定义万能装饰器
def 装饰器名称(f):
def wrapper(*args, **kwargs):
# 函数执行之前的操作
f(*args, **kwargs)
# 函数执行之后的操作
return wrapper
def 装饰器名称(f):
def wrapper(*args, **kwargs):
if 条件:
f(*args, **kwargs)
else:
# 报错并抛出异常 raise Error("xxxxxx")
return wrapper
2.有参数的装饰器
def 有参数的装饰器(*args, **kwargs):
def 装饰器名称(f):
def wrapper(*args, **kwargs):
if 条件:
f(*args, **kwargs)
else:
# 报错并抛出异常 raise Error("xxxxxx")
return wrapper
return 装饰器名称
3.装饰器底层原理
@timmer # fun = timmer(fun)
def fun():
pass
4.functools: 保留原有函数的名称(f.name)和文档帮助等信息;
def 装饰器名称(f):
@functools.wrap(f)
def wrapper(*args, **kwargs):
if 条件:
f(*args, **kwargs)
else:
# 报错并抛出异常 raise Error("xxxxxx")
return wrapper
5.inspect:
不管是默认参数, 必选参数, 可变参数, 关键子参数, 都会将形式参数和传的值封装为字典;便于使用;