python之装饰器

装饰器:

概念:把一个函数当作参数传递给一个函数,返回一个替代版的函数
本质上就是一个返回函数的函数
“在不改变原函数的基础上,给函数增加功能”

# def outer(func):
#     def inner():
#         print('*****')
#         func()
#     return inner
#
# @outer
# def func1():
#     print('have a nice day!')

# @outer
# def func2():
#     print('hello world')

# func1()
# func2()
*****
have a nice day!
*****
hello world
    
    
import time

# def desc(f):  # 需要传递的函数(要装饰的函数)
#     def add():
#         print('儿童节快乐~~~')
#         f()
#         print('~~~~~~~~')
#
#     return add
#
#
# @desc
# def login():
#     print('login...')
#
#
# @desc
# def logout():
#     print('logout....')
# login()
# logout()
#
儿童节快乐~~~
login...
~~~~~~~~
儿童节快乐~~~
logout....
~~~~~~~~

# def savemoney():
#     print('savemoney.....')
#
#
# def transfermoney():
#     print('transfermoney....')
#
#
# login()

print(time.time())
问题1:被装饰的函数有返回值的时候怎么办?
 def timeit(fun): 
    def wapper(*args, **kwargs):  
        start_time = time.time() 
        res = fun(*args, **kwargs) 
        end_time = time.time()
        print('运行的时间为:%.6f' % (end_time - start_time))
        return res
    return wapper
问题2:被装饰的函数如何保留自己的函数名和帮助信息文档?
import time
import string
import random 
st = [random.choice(string.ascii_letters)
      for i in range(1000)]

def fairy(fun):
    def wapper(*args, **kwargs):
        """这是一个wapper函数"""
        start_time = time.time()
        fun(*args, **kwargs)
        end_time = time.time()
        print('运行的时间为:%.6f %s' % (end_time - start_time,fun.__name__))
    return wapper

@fairy
def join_add():
	"""这是连接函数哟"""
    print('+'.join(st))

join_add()
print(join_add.__name__)
print(join_add.__doc__)

z+Z+U+J+F+U+E+G+y+H+q+J+L+o+B+Z+g+P+z+e+k+H+n+H+q+E+I+O+x+s+w+V+z+W+e+i+f+c+y+f+g+J+q+f+N+q+c+j+q+E+W+B+j+P+t+j+r+G+r+a+R+W+J+Q+V+F+k+I+P+r+F+f+g+e+p+c+N+t+S+t+u+Z+r+o+E+i+Q+N+L+l+k+m+z+V+n+L+J+N+x+e+n+V+o+F+I+Q+J+B+u+i+d+e+a+p+o+V+W+i+U+v+d+M+G+f+x+k+O+G+V+A+Y+M+n+G+p+L+i+C+O+r+w+g+h+P+p+g+N+P+j+y+N+d+I+c+Z+V+x+z+Y+i+R+Y+t+b+q+A+m+V+w+G+K+O+A+R+r+r+B+E+W+Z+W+u+z+b+m+h+D+M+t+h+T+P+a+h+z+J+m+n+S+Q+f+U+Y+W+h+c+O+f+o+Z+O+c+b+n+x+J+M+i+D+k+g+q+r+T+X+Y+E+f+Z+A+h+Q+g+f+s+A+d+c+Z+W+z+q+p+j+P+I+z+Q+k+D+T+X+m+M+p+I+Z+g+Q+L+B+e+x+K+K+m+A+A+T+T+B+l+n+O+l+O+i+z+m+m+J+O+V+A+f+m+Z+A+M+Q+T+X+d+U+C+h+C+X+P+C+r+o+H+V+a+m+j+t+T+d+v+n+N+A+s+i+C+j+E+M+g+Q+s+p+o+D+f+q+l+j+x+Q+r+s+v+R+Z+i+V+Z+m+f+U+m+Q+O+z+F+c+Y+b+R+N+a+G+o+R+p+R+d+R+i+E+m+p+D+L+K+r+e+w+l+g+W+Q+f+p+Z+b+T+O+r+k+e+o+B+h+X+e+m+F+g+c+P+D+j+d+I+N+Z+G+g+J+T+a+C+y+N+O+T+B+l+Z+k+s+L+p+p+j+A+v+R+l+q+q+d+F+y+i+E+h+b+n+x+L+j+F+J+n+n+w+H+i+V+L+d+I+x+K+Q+c+H+I+B+b+B+H+D+i+t+O+k+q+Y+H+b+Q+c+w+v+s+G+s+p+J+w+C+W+o+v+M+p+m+F+l+U+U+v+a+C+W+u+D+L+e+x+v+D+N+R+z+g+w+D+Z+C+t+v+P+p+F+I+w+V+m+N+j+w+q+P+T+N+A+b+h+M+i+I+f+I+D+C+x+m+g+d+g+S+k+E+K+J+m+b+D+a+e+h+T+M+d+B+F+P+u+m+l+L+G+Y+v+k+S+Z+n+P+I+C+t+r+L+K+M+h+a+p+V+t+P+z+F+b+j+U+a+F+M+V+o+L+c+g+s+U+f+H+V+Q+E+a+P+m+H+n+r+K+g+K+d+F+x+d+Q+J+J+I+O+h+v+H+D+H+I+J+T+e+m+W+x+q+O+y+T+K+f+v+q+j+Y+y+P+K+y+K+n+F+n+l+X+G+a+Z+M+U+y+I+V+D+t+T+c+t+m+Y+b+k+i+s+E+p+c+w+K+o+r+S+d+w+R+r+u+s+z+H+K+U+V+p+v+c+D+E+V+W+e+q+B+J+X+t+P+l+Q+i+y+M+S+I+r+u+X+w+V+G+v+U+c+R+t+w+h+r+l+c+y+R+J+a+E+k+i+h+O+D+E+z+x+I+S+j+a+x+K+p+g+P+S+t+v+q+L+E+Y+A+M+X+M+a+t+R+C+k+v+X+j+a+O+b+i+B+c+z+d+O+C+M+Y+E+d+T+U+t+p+P+t+f+w+S+S+g+B+J+a+R+Z+f+f+W+I+R+m+j+I+I+j+e+D+Z+i+g+D+V+m+I+i+b+z+H+N+B+S+Y+Y+I+v+H+v+Y+I+r+g+D+G+e+r+d+P+a+m+U+R+y+v+a+p+X+q+q+g+z+Y+t+A+s+d+Y+p+b+J+P+R+b+k+N+Z+X+e+W+Z+h+t+e+G+j+Z+s+k+O+g+p+I+P+P+v+r+m+O+i+Q+K+E+q+f+S+y+j+a+Q+C+f+M+V+f+n+f+n+c+V+Y+L+a+H+L+t+J+Z+F+A+E+y+O+A+w+A+Z+K+o+E+o+S+D+t+l+l+T+t+u+w+k+m+o+p+q+H+c+w+o+L+Q+y+V+S+o+c+y+x+K+f+q+m+z+n+b+l+x+h+k+c+W+o+W+t+P+f+v+y+u+H+H+o+P+o+V+m+T+l+l+f+O+M+M+u+r+m+x+e+r+S+d+D
运行的时间为:0.000036 join_add
wapper
这是一个wapper函数

可以看出这里的输出是有问题的
函数的名称和帮助文档和我们想要的不一样
使用functools中的wraps可以很好的解决这个问题
注意:@functools.wraps(fun)中的fun必须和def fairy(fun)的fun一致。

import time
import string
import random
import functools
st = [random.choice(string.ascii_letters)
      for i in range(1000)]

def fairy(fun):
    @functools.wraps(fun)
    def wapper(*args, **kwargs):
        """这是一个wapper函数"""
        start_time = time.time()
        fun(*args, **kwargs)
        end_time = time.time()
        print('运行的时间为:%.6f %s' % (end_time - start_time,fun.__name__))
    return wapper

@fairy
def join_add():
    """这是一个连接函数哟"""
    print('+'.join(st))

join_add()
print(join_add.__name__)
print(join_add.__doc__)
J+W+j+B+C+m+v+E+O+J+Y+t+x+f+d+G+X+W+c+M+f+z+x+H+w+h+y+s+U+P+t+T+k+t+v+W+p+O+e+G+N+W+N+o+R+X+h+g+G+y+I+C+B+U+u+c+W+Y+c+B+E+j+Z+E+e+X+Q+y+N+b+u+u+t+h+b+g+I+H+Y+l+q+L+j+J+b+L+N+b+e+A+K+G+s+d+r+Y+S+t+U+X+P+F+g+h+Z+d+d+I+m+f+X+z+B+Q+E+L+E+O+R+B+V+D+P+J+s+E+e+Q+h+G+x+k+V+A+W+W+g+c+w+f+I+P+x+G+J+S+d+o+B+j+u+l+r+G+z+n+M+d+m+h+b+A+I+p+X+t+X+Q+Y+T+P+E+a+Q+g+V+Q+i+S+Z+H+w+h+o+y+J+U+n+H+L+P+x+T+Z+f+K+k+Z+Q+F+t+z+D+l+u+S+d+G+q+U+B+c+Q+t+j+k+N+j+X+q+a+P+B+X+L+z+A+y+t+N+P+P+k+V+d+q+n+Q+H+M+K+s+g+o+F+X+a+V+b+M+P+a+r+x+z+B+I+m+w+X+f+y+Y+x+n+l+J+c+t+q+U+z+w+E+n+V+e+G+E+d+x+H+P+S+B+i+x+l+Z+b+l+m+d+u+C+X+y+D+m+S+o+x+B+X+h+h+Y+G+B+E+I+I+m+x+X+h+W+V+Z+s+H+k+w+F+X+Y+q+X+b+P+w+E+d+H+e+r+n+Y+Q+N+J+c+p+l+t+k+L+K+e+c+x+B+D+z+t+t+V+h+t+x+q+x+A+M+z+m+X+W+p+j+m+R+a+c+x+g+J+V+i+O+X+k+v+u+a+J+q+C+W+N+l+W+r+z+J+W+d+C+j+r+B+G+I+X+F+q+U+u+p+q+l+r+Q+i+x+P+n+D+w+M+E+Z+W+u+D+w+m+X+y+W+j+L+F+o+I+P+C+o+z+W+W+x+m+x+l+C+W+J+V+q+v+N+J+S+W+Y+y+v+o+C+O+E+b+H+Q+u+w+y+K+I+d+a+c+Y+M+p+n+l+Q+y+Z+M+P+u+w+u+q+R+R+M+x+A+I+X+T+x+y+R+Y+a+d+N+F+N+x+T+E+I+o+q+h+T+q+D+G+x+w+p+s+A+g+o+P+o+U+b+V+W+d+E+Q+E+B+E+O+S+b+s+F+D+n+n+i+W+B+x+C+o+g+e+e+X+W+K+f+A+J+q+W+e+S+J+h+q+J+j+M+K+w+b+L+C+o+x+l+S+I+U+W+h+k+r+A+z+Q+m+B+i+I+R+f+h+b+k+O+Q+c+b+y+N+I+j+o+s+J+h+N+g+P+i+l+W+l+L+s+w+S+d+Q+r+S+O+v+r+c+e+u+Y+Z+o+L+q+i+a+S+Y+w+y+c+S+m+f+J+C+t+o+J+X+b+C+R+G+T+O+n+S+A+F+C+C+D+x+F+N+h+p+H+B+a+J+V+S+K+p+a+V+n+z+q+X+t+J+Y+S+n+F+g+m+S+d+a+t+v+k+x+e+R+P+J+d+b+w+Z+a+F+d+e+a+M+p+Y+G+m+w+c+c+r+A+H+J+B+r+m+d+M+v+G+w+m+A+W+u+k+t+g+i+R+f+y+c+I+I+c+a+h+N+l+a+u+l+o+M+E+i+O+X+H+i+M+k+s+j+G+d+K+c+S+Z+w+D+x+X+e+W+m+b+v+Y+K+N+b+B+F+i+t+X+M+H+q+X+J+c+p+q+g+M+R+S+R+T+u+t+b+V+q+b+b+V+G+H+S+s+L+c+s+l+y+X+E+S+c+R+Y+a+q+B+O+y+q+G+e+X+O+S+q+p+W+v+H+P+O+c+B+i+s+T+G+z+b+p+s+j+U+A+i+G+B+l+Y+y+d+W+C+Y+n+W+M+S+N+Z+k+E+B+u+V+E+W+Q+F+V+h+L+x+D+c+C+W+n+a+T+Z+R+m+m+v+t+r+I+p+Q+o+B+Y+d+v+v+w+v+C+q+X+n+X+L+W+H+q+W+c+H+P+N+B+z+h+J+k+S+r+E+y+w+t+k+Z+f+e+p+w+g+E+g+T+U+l+F+d+Z+Y+Q+v+Y+p+h+l+K+x+w+x+p+l+C+Y+y+t+y+s+w+h+B+z+Y+m+o+K+B+P+B+E+g+Y+q+O+b+i+C+l+L+g+Z+h+v+M+L+x+Z+n+J+J+C
运行的时间为:0.000036 join_add
join_add
这是一个连接函数哟
创建装饰器, 要求如下:
  1. 创建add_log装饰器, 被装饰的函数打印日志信息;
  2. 日志格式为: [字符串时间] 函数名: xxx,运行时间:xxx, 运行返回值结果:xxx
import time
import functools

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 wrapper
@add_log
def add(x,y):
    time.sleep(1)
    return x+y
add(1,10)

[Mon Jun 10 23:54:32 2019] 函数名:add,运行时间:1.001054,运行返回值的结果:11

多个装饰器装饰函数[如何调用]

def warpper1(func):  
    def inner1():
        print('warpper1')  
        func()  
        print('warpper1rear')  
    return inner1

def warpper2(func): 
    def inner2():
        print('warpper2')  
        func()  
        print('warpper2rear')  
    return inner2

@warpper1  
@warpper2  
def f():
    print('你好')  

f()  #warpper1(warpper2(f()))

warpper1
warpper2
你好
warpper2rear
warpper1rear

----------------------有返回值的情况-----------------------
def decorator_a(fun):
    def inner_a(*args,**kwargs):
        print('Get in inner_a')
        return fun(*args,**kwargs)
    return inner_a

def 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*2

print(f(1))

Get in inner_b
Get in inner_a
Gat in f
2

多个装饰器的应用场景:

会采用多个装饰器先验证是否登陆成功,再验证登陆权限是否足够

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 temp
        else:
            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 temp
        else:
            print('Error:%s 没有登陆成功' %(args[0]))
    return wrapper
@is_login
@is_admin
def add_user(name):
    print('add user~')
add_user('root')

带参数的装饰器

import functools
import time

def 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 res
        return wrapper
    return 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类型
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值