装饰器概念:
把一个函数当作参数传递给一个函数,返回一个替代版的函数
本质上就是一个返回函数的函数
在不改变原函数的基础上,给函数增加功能
python 中装饰器做的事情!它们封装一个函数,并且用这样或者那样的方式来修改它的行为
@ 符号,那只是一个简短的方式来生成一个被装饰的函数
def outer(func):def inner():print('*****')func()return inner@outer
def func():print('have a nice day!')
@outer
def func2():print('hello world')
func()
func2()运行结果:
*****
have a nice day!
*****
hello world
装饰器示例:
import time# 装饰器
def decorator(func):def wrapper():print(time.time())func()return wrapper@decorator # 调用装饰器
def f1():print('This is a function...')def f2(): # 没有装饰器print('This is a function...')f1()
f2()运行结果:
1560391414.8582878 f1
This is a function...
This is a function... f2
装饰器实现一个函数计时器
import time
import string
import random
import functoolsli = [random.choice(string.ascii_letters)for i in range(1000)]def timeit(fun):# 问题1:被装饰的函数有返回值的时候怎么办?# 问题2:被装饰的函数如何保留自己的函数名和帮助信息文档?@functools.wraps(fun)def wapper(*args, **kwargs):"""这是一个wapper函数"""# 在函数的执行之前start_time = time.time()# 执行函数res = fun(*args, **kwargs)# 在函数执行之后end_time = time.time()print('运行的时间为:%.6f' % (end_time - start_time))return resreturn wapper@timeit
def con_add():s = ''for i in li:s += (i + '+')print(s)@timeit
def join_add():print('+'.join(li))con_add()
join_add()@timeit
def fun_list(n):"""这是fun_list函数,被timeit装饰"""return [2 * i for i in range(n)]
@timeit
def fun_map(n):"""这是fun_map函数,被timeit装饰"""return list(map(lambda x:x*2,range(n)))# fun_list(5000)
# fun_map(5000)
print(fun_list.__doc__)
print(fun_map.__doc__)
print(fun_list.__name__)
print(fun_map.__name__)
创建装饰器, 要求如下:
1 . 创建add_log装饰器, 被装饰的函数打印日志信息;
2 . 日志格式为: [字符串时间] 函数名: xxx,
运行时间:xxx, 运行返回值结果:xxx
import time
import functools
print(time.ctime())def add_log(func):@functools.wraps(func)def wrapper(*args,**kwargs):start_time = time.time()res = func(*args,**kwargs)end_time = time.time()print('[%s] 函数名:%s,运行时间:%.6f,运行返回值的''结果:%d' %(time.ctime(),func.__name__,end_time-start_time,res))return resreturn wrapper
@add_log
def add(x,y):time.sleep(1)return x+y
add(1,10)
多个装饰器装饰函数,从上到下执行
def decorator_a(fun):def inner_a(*args,**kwargs):print('Get in inner_a')return fun(*args,**kwargs)return inner_adef decorator_b(fun):def inner_b(*args,**kwargs):print('Get in inner_b')return fun(*args,**kwargs)return inner_b@decorator_b
@decorator_a
def f(x):print('Gat in f')return x*2f(1)
多个装饰器的应用场景:
会采用多个装饰器先验证是否登陆成功,再验证登陆权限是否足够
inspect.getcallargs会返回一个字典,
import inspect
import functools
def is_admin(fun):@functools.wraps(fun)def wrapper(*args,**kwargs):# inspect.getcallargs 会返回一个字典,# key值:形参 value:对应的实参数inspect_res = inspect.getcallargs(fun,*args,**kwargs)print('inspect的返回值是:%s' %(inspect_res))if inspect_res.get('name') == 'root':temp = fun(*args,**kwargs)return tempelse:print('not root user,no permisson add user')return wrapper
login_session = ['root','admin','redhat']def is_login(fun):@functools.wraps(fun)def wrapper(*args,**kwargs):if args[0] in login_session:temp = fun(*args,**kwargs)return tempelse:print('Error:%s 没有登陆成功' %(args[0]))return wrapper
@is_login
@is_admin
def add_user(name):print('add user~')
add_user('root')
代参数的装饰器
import functools
import timedef log(kind):def add_log(func):@functools.wraps(func)def wrapper(*args,**kwargs):start_time = time.time()res = func(*args,**kwargs)end_time = time.time()print('<%s>[%s] 函数名:%s,运行时间:%.6f,运行返回值的''结果:%d' %(kind,time.ctime(),func.__name__,end_time-start_time,res))return resreturn wrapperreturn add_log
@log('debug')
def add(x,y):time.sleep(1)return x+y
print(add(1,2))
练习题:
编写装饰器required_types, 条件如下:
1). 当装饰器为@required_types(int,float)确保函数接收到的每一个参数都是int或者float类型;
2). 当装饰器为@required_types(list)确保函数接收到的每一个参数都是list类型;
3). 当装饰器为@required_types(str,int)确保函数接收到的每一个参数都是str或者int类型;
4). 如果参数不满足条件, 打印 TypeError:参数必须为xxxx类型
import functools
def required_types(*kinds):def required_int(fun):@functools.wraps(fun)def wrapper(*args, **kwargs):for i in args:if not isinstance(i, kinds):# print('TypeError:参数必须为',kinds)# breakraise TypeError('参数必须为%s,%s' % kinds)else:res = fun(*args, **kwargs)return resreturn wrapperreturn required_int# @required_types(float, float)
# def add(a, b):
# return a + b
#
# print(add(1.1, 2.0))
运行结果为:3.1# @required_types(list)
# def add(a, b):
# return a + b
#
# print(add(1.1, 2.0))
运行结果为:
Traceback (most recent call last):File "/home/kiosk/PycharmProjects/20190523/练习.py", line 65, in <module>print(add(1.1, 2.0))File "/home/kiosk/PycharmProjects/20190523/练习.py", line 42, in wrapperraise TypeError('参数必须为%s,%s' % kinds)
TypeError: not enough arguments for format string