【PYTHON】装饰器(Decorator)介绍

- - 看了两三篇博客。
其中有一篇虽然
* 错字连篇
* 代码错误
* 逻辑混乱

但是将decorator 循序渐进实现的思路值得记录一下。 故在此回顾一下什么是decorator。


为什么要使用装饰器

  1. 并不希望修改原有函数的代码
  2. 并不希望修改调用原有函数的方式
  3. 希望在满足1,2的前提下给原函数增加新的功能

有点像java的aop的感觉。

我们逐步看一下如何实现…


假设我们有个函数 process(*args)我们希望在调用的时候对他进行计时,打印出来这个函数的执行时间。

以下写法全部都不会改写process(*args) 本身

solution1

import time

def process():  # 实际的处理函数,具体做什么我们不关心
    time.sleep(2)

def wrapper():
    print('开始执行... ')
    start = time.time()
    process()
    end = time.time()
    print('耗时 %s s' %(end-start))

wrapper()

执行结果

开始执行... 
耗时 2.0006916522979736 s

这种看似没什么问题,却违背了我们 2. 并不希望修改调用原有函数的方式 这一原则。 原本我们调用process()只需要 process() 就好了,现在变成了wrapper()或者说可以包装进去成 wrapper(process)

solution2

# 略去process() 的定义 以及import部分

def decorator(func):
    def wrapper(*args, **kwargs):  # 表示process函数中可以任意入参
        print('开始执行... ')
        start = time.time()
        func(*args, **kwargs)
        end = time.time()
        print('耗时 %s s' %(end-start))
    return wrapper

process = decorator(process)

process()

执行结果

开始执行... 
耗时 2.0006916522979736 s

这种调用方式就足够完美了,通过这种方式我们初步实现了装饰器。
process = decorator(process) 这个地方将process作为入参传入装饰器并封存等待调用。

更高级的写法是


def decorator(func):
    def wrapper(*args, **kwargs):
        print('开始执行... ')
        start = time.time()
        func(*args, **kwargs)
        end = time.time()
        print('耗时 %s s' %(end-start))
    return wrapper

@decorator
def process():
    time.sleep(2)

process()

注解的作用相当于 process = decorator(process)

solution3

如果process有返回值怎么办?

目前的写法只能返回wrapper,然后让wrapper()去调用到内部的process(),返回值也会消耗在wrapper()的内部。

def decorator(func):
    def wrapper(*args, **kwargs):
        print('开始执行... ')
        start = time.time()
        res = func(*args, **kwargs)
        end = time.time()
        print('耗时 %s s' % (end - start))
        return res
    return wrapper

@decorator
def process():
    time.sleep(2)
    return 'OMG'

print(process())

结果是:

开始执行... 
耗时 2.0006561279296875 s
OMG

还不够完美,@注解的方式还可以注入参数

final solution

def timer(text):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print('%s 开始执行... ' % text)
            start = time.time()
            res = func(*args, **kwargs)
            end = time.time()
            print('%s 耗时 %s s' % (text,(end - start)))
            return res
        return wrapper
    return decorator

@timer('无敌YF')
def process():
    time.sleep(2)
    return 'OMG'

print(process())

如果还需要在某个新的层级上添加新的入参,还需要再嵌套一层。

如上的写法相当于


timer = timer('无敌YF')
process = decorator(process) # 需要好好对照代码去理解。。

思考题:

final solution的代码中

print(process.__name__)  

结果会是什么呢??

Answer is

wrapper

这是不对的,我们的process的属性经过包装后发生了变化,返回的是wrapper的__name__, 尽管这是很小的一点,但也是不正确的是错误的。我们需要修正这一点。

Real Final Solution

import time
import functools

def timer(text):
    def decorator(func):
        @functools.wraps(func)  # 将func的相应属性赋值给wrapper
        def wrapper(*args, **kwargs):
            print('%s 开始执行... ' % text)
            start = time.time()
            res = func(*args, **kwargs)
            end = time.time()
            print('%s 耗时 %s s' % (text,(end - start)))
            return res
        return wrapper
    return decorator

@timer('无敌YF')
def process():
    time.sleep(2)
    return 'OMG'

print(process())

print(process.__name__)  # 此时就会如实的打印出process

就此,Decorator的介绍就算是正式结束了。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值