Python中的装饰器(Decorator)

一、装饰器的概念

在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)

装饰器的作用是在原有的函数基础上外包一个函数,增加新的功能。

本质上就是一个返回函数的高阶函数。

二、装饰器的原理

装饰器是在原来函数基础上外包一个函数,增加新功能。

如果:

原函数A

则:

装饰器D可为:

def D(A):
    def W(*args,**kw):
        #新功能
        return A(*args,**kw)
    return W

三、一个log函数的例子

下面我们来看一个log函数的经典装饰器例子。

def log(func):
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper

上述函数的设计逻辑是:

step1,将func函数作为参数传入log,

step2,在log函数中内置一个函数wrapper作为增加功能的函数,并计算(当然,本例中只是函数名打印出来)

step3,以func作为返回值,完成wrapper任务。

step4,最后,返回wrapper函数。

        wrapper函数携带的是新功能(那句打印print函数名)+原本的func函数执行结果

四、装饰器调用

接下来,我们看看装饰器log如何使用。

利用python的@语法将log置于函数定义前

@log
def now():
    print(‘2019-11-27’)

其中,

@log相当于

now = log(now)

运行now()则打印如下结果

call now():
2019-11-27

五、传入参数的装饰器

decorator本身也可以传入参数

需要外层再进行包装

def log(text):
    def decorator(func):
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator

用法:

@log(‘execute’)
def now():
    print(‘2019-11-27’)

执行now()

结果为:

execute now():
2019-11-27

上面三层嵌套的原理如下:

@log(‘execute’)
def now():……

相当于:

def now():……
now = log('execute')(now)

我们剖析上面的语句

        首先执行log('execute'),返回的是decorator函数。

        再调用返回的函数,参数是now函数,返回值最终是wrapper函数。

六、decorator的隐含问题

经过修饰的函数__name__发生了改变。

>>>now.__name__
‘wrapper’

有些依赖函数签名的代码执行就会出错。

解决方案

        1.wrapper.__name__ = func.__name__  (不推荐)

        2.Python内置的functools.wraps

代码如下:

不带参数的装饰器:

import functools

def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper

带参数的装饰器

import functools

def log(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator

七、实例:请设计一个decorator,它可作用于任何函数上,并打印该函数的执行时间

# -*- coding: utf-8 -*-
import time, functools

#请设计一个decorator,它可作用于任何函数上,并打印该函数的执行时间:

def metric(fn):
    @functools.wraps(fn)
    def wrapper(*args, **kw):
        sta_time = time.time()
        func = fn(*args, **kw)
        end_time = time.time()
        print('%s executed in %s ms' % (fn.__name__, end_time - sta_time))
        return func
    return wrapper


# 测试
@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('测试失败!')

学会了就点个赞吧。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猎风工作室

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值