python中的装饰器(定义、应用场景、练习题)

1.装饰器定义
把一个函数当作参数,返回一个替代版的函数
本质上就是一个返回函数的函数
作用:在不改变原函数的基础上,给函数增加功能
2.装饰器的应用
2.1没有使用装饰器的情况
方法一:

def fun():
    print('hello westos')
fun()
打印结果
hello westos

给上面函数内添加内容:
def fun():
    print('hello world')
    print('hello westos')
fun()
打印结果   成功添加了但是改变了函数的整体内容
hello world
hello westos

方法二:

def fun():
    #print('hello world')
    print('hello westos')
#fun()
def outher():
    print('hello world')
    fun()
outher()
打印结果   成功添加但是改变了调用函数名称
hello world
hello westos

方法三:

import time  导入时间
def decorator(fun):   定义装饰器函数
    def wrapper():  定义装饰器内部函数也就是要添加的函数(元素)
        print(time.time())   定义添加内容
        fun()      形参:代表下方的f1()函数
    return wrapper  返回warpper函数  让warpper函数运行,若不返回则下方调用无效,
def f1():           不加括号表示返回函数本身,带括号表示返回结果,此函数没有结果
    print('meng')
f = decorator(f1)      定义名称f 调用装饰器函数 
f()                 函数名发生改变
打印结果    
1587872633.0011702
meng

2.2使用装饰器给函数增添新的功,在已经写好的函数上添加新内容

import time  导入时间函数
def desorator(fun):   定义装饰器函数
    def wrapper(*args,**kwargs):  定义装饰器内部函数
        print(time.time())  打印时间从1970年开始
        fun(*args,**kwargs)  调用函数
    return warpper  返回函数
@desorator  使用装饰器给f函数添加打印时间功能
def f():                     
    print('hello westos')
f()  
打印结果
1587875340.6591613
hello westos

2.3装饰器传入参数

import  time
def decorator(fun):
    def wrapper(*args,**kwargs):
        print(time.time())
        fun(*args,**kwargs)
    return wrapper
@decorator
def f(fun_name1,fun_name2,**kwargs):
    print('hello westos' + fun_name1)
    print('hello westos' + fun_name2)
    print(kwargs)
f('test1','test2',a=1,b=2,c='westos')
打印结果
1587880978.5839212
hello westostest1
hello westostest2
{'a': 1, 'b': 2, 'c': 'westos'}

2.4装饰器设置可变参数

import  time
def decorator(fun):
    def wrapper(*args,**kwargs):
        print(time.time())
        fun(*args,**kwargs)
    return wrapper
@decorator
def f(fun_name1,fun_name2,**kwargs):
    print('hello westos' + fun_name1)
    print('hello westos' + fun_name2)
f('test1','test2')
打印结果
1587881108.6572278
hello westostest1
hello westostest2

2.5装饰器可以设置关键字参数

import  time
def decorator(fun):
    def wrapper(*args,**kwargs):
        print(time.time())
        fun(*args,**kwargs)
    return wrapper
@decorator
def f(fun_name1,fun_name2,**kwargs):
    print('hello westos' + fun_name1)
    print('hello westos' + fun_name2)
    print(kwargs)
f('test1','test2',a=1,b='hello',c='python')
打印结果
1587881250.1230538
hello westostest1
hello westostest2
{'a': 1, 'b': 'hello', 'c': 'python'}

应用场景及习题
装饰器实现一个函数计时器

i

mport time   时间模块(import time)
import functools   用于高阶函数:指那些作用于函数或者返回其它函数的函数,通常只要是可以被当做函数调用的对象就是这个模块的目标
def timetest(fun):
    """这是一个装饰器"""
    @functools.wraps(fun)
    def wrapper(*args,**kwargs):
        start_time = time.time()
        res = fun(*args,**kwargs)
        end_time = time.time()
        print('运行时间:是%.6f' % (end_time - start_time))
        return res  返回值
    return wrapper
@timetest
def fun_list(n):
    """这是一个fun_list函数"""
    return [2 *i for i in range(n)]  列表生成式
@timetest
def fun_map(n):
    """这是一个fun_map函数"""
    return list(map(lambda x:x*2,range(n)))   匿名函数
print(fun_list(1000))
print(fun_map(1000)

打印结果
在这里插入图片描述

import random
import string
import time
import functools
li = [random.choice(string.ascii_letters) for i in range(5)]
print(li)
def timetest(fun):
    """这是一个装饰器"""
    @functools.wraps(fun)
    def wrapper(*args,**kwargs):
        start_time = time.time()
        res = fun(*args,**kwargs)
        end_time = time.time()
        print('运行时间为:%.6f' %(end_time - start_time))
        return res
    return wrapper
@timetest
def con_add():
    """这是一个con_add函数"""
    s = ' '
    for i in li:
        s += (i+',')
    print(s)
@timetest
def join_add():
    """这是一个jion_add函数"""
    print(','.join(li))
con_add()
join_add()
print(con_add.__doc__)
print(join_add.__doc__)
打印结果
['J', 'P', 'Q', 'K', 'S']
 J,P,Q,K,S,
运行时间为:0.000015
J,P,Q,K,S
运行时间为:0.000005
这是一个con_add函数
这是一个jion_add函数

创建装饰器, 要求如下:

  1. 创建add_log装饰器, 被装饰的函数打印日志信息;
  2. 日志格式为: [字符串时间] 函数名: xxx, 运行时间:xxx, 运行返回
    值结果:xxx
time.sleep()函数推迟调用线程的运行,可通过参数secs指秒数,表示进程挂起的时间语法格式:time.sleep(t)
import time 
import functools
def add_log(fun):
    @functools.wraps(fun)
    def wrapper(*args,**kwargs):
        start_time = time.time()
        res = fun(*args,**kwargs)
        end_time = time.time()
        print('[%s]函数名:%s运行时间:%.6f,运行返回值结果:%d'
              % (time.ctime(), fun.__name__, end_time - start_time, res))
        return res
    return wrapper
@add_log
def add(x,y):
    time.sleep(1)    
    return x + y
add(2,5)
打印结果
[Sun Apr 26 15:46:02 2020] 函数名:add 运行时间:1.001615,运行返回值结果:7
之前的装饰器传入的参数都是函数,返回值也是函数
现在给装饰器传入一般参数
装饰器也是函数,现在只需要再装饰器外面再加一层装饰器就可以变为函数传入函数

编写装饰器required_types, 条件如下:
1). 当装饰器为@required_types(int,float)确保函数接收到的每一>个参数都是int或者float类型;
2). 当装饰器为@required_types(list)确保函数接收到的每一个参数
都是list类型;
3). 当装饰器为@required_types(str,int)确保函数接收到的每一个>参数都是str或者int类型;
4). 如果参数不满足条件, 打印 TypeError:参数必须为xxxx类型

 sinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()isinstance()type() 区别:
type() 不会认为子类是一种父类类型,不考虑继承关系。
isinstance() 会认为子类是一种父类类型,考虑继承关系。
如果要判断两个类型是否相同推荐使用 isinstance()isinstance(object, classinfo)
>>>a = 2
>>> isinstance (a,int)
True
>>> isinstance (a,str)
False
>>> isinstance (a,(str,int,list))    是元组中的一个返回 True
True
import  functools
def required_types(*kind):  最外面定义一个装饰器*kind表示接受多个元素
    def required(fun):  里面的装饰器
        @functools.wraps(fun)
        def wrapper(*args,**kwargs):
            for i in args:
                if not isinstance(i,kind):    
                    print('TypeError:参数必须为%s,%s类型' %kind)
                    exit()
            else:
                res = fun(*args,**kwargs)
                return res
        return wrapper
    return required
@required_types(float,float)  调用最外层函数float浮点型,表示有小数点的数值整型
def add(x,y):
    return x+y
print(add(3.3,3.3))
print(add(2,5.5))
打印结果6.6
TypeError:参数必须为<class 'float'>,<class 'float'>类型’

多个装饰器执行顺序

def decorator_a(fun):   第一个装饰器
    def inner_a(*args,**kwargs):
        print('get in inner_a')
        return fun(*args,**kwargs)
    return inner_a
def decortor_b(fun):  第二个装饰器
    def inner_b(*args,**kwargs):
        print('get in inner_b')
        return fun(*args,**kwargs)
    return inner_b
@decorator_a 先调用那个装饰器,那个就先运行
@decortor_b
def f(x):
    print('get in f')
    return x*3
f(1)
@decortor_b
@decorator_a
def f(x):
    print('get in f')
    return x*3
f(1)
打印结果
get in inner_a
get in inner_b
get in f
get in inner_b
get in inner_a
get in f
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值