Python进阶篇--装饰器

装饰器是Python中的魔法所在,下边让我们来一探究竟。
话不多说, 上代码。
前菜

from functools import wraps
import time


def timethis(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print("The running time is ", end-start)
        return result
    return wrapper


@timethis
def add(x, y):
    res = []
    for i in range(100000):
        res.append(x+y)
    return res


if __name__ == "__main__":
    a = add(5, 10)
    print(a)

装饰器的运作原理其实很简单,添加@timethis会发生什么?下面就一一道来。其实就是简单的把add函数包裹了一下。
func = timethis(func), timethis 里边的@wraps(func)一定要加,不然访问不到函数的元信息。 比如你想使用原始的函数而不是包裹后函数。你可以使用__wrapped__属性。
ori_add = add.wrapped
ori_add(5, 10)
如果不加@wraps(func),程序运行就会报错。

前菜可还可口?几下来主菜要来了
主菜 带参数的装饰器

from functools import wraps
import logging

logging.basicConfig(level=logging.DEBUG)


def logged(level, name=None, msg=None):

    def decorator(func):
        logname = name
        log = logging.getLogger(logname)
        logmsg = msg

        @wraps(func)
        def wrapper(*args, **kwargs):
            log.log(level, logmsg)
            return func(*args, **kwargs)
        
        return wrapper
    
    return decorator


@logged(logging.DEBUG, "add", "This is an add function")
def add(x, y):
    return x + y


if __name__ == "__main__":
    add(3, 5)

添加logged装饰器,其实和下边的代码时等价的。
new_add = logged(logging.DEBUG, “add”, “This is an add function”)(func)
这样就又回到前菜了,可以体会一下, 其实所有的装饰器都时这样工作的,掌握本质才是真正学会一个东西。

大餐来了 给wrapper添加属性

from functools import wraps, partial
import logging


logging.basicConfig(level=logging.DEBUG)


def attach_wrapper(obj, func=None):
    if func is None:
        return partial(attach_wrapper, obj)
    setattr(obj, func.__name__, func)
    return func


def logged(level, name=None, msg=None):

    def decorator(func):
        logname = name
        log = logging.getLogger(logname)
        logmsg = msg

        @wraps(func)
        def wrapper(*args, **kwargs):
            log.log(level, logmsg)
            return func(*args, **kwargs)

        @attach_wrapper(wrapper)
        def set_level(newlevel):
            nonlocal level
            level = newlevel

        @attach_wrapper(wrapper)
        def set_msg(newmsg):
            nonlocal logmsg
            logmsg = newmsg

        return wrapper

    return decorator


@logged(logging.DEBUG, "add", "This is an add function")
def add(x, y):
    return x + y


if __name__ == "__main__":
    add(3, 5)
    add.set_level(logging.CRITICAL)
    add(3, 4)
    add.set_msg("This is testing attaching attr")
    add(5, 6)

上面这段代码核心时attach_wrapper()这个函数,这个函数主要作用其实就是给wrapper对象添加两个属性set_level和set_msg.这样我们就能在包裹后的add函数中访问这两个属性了。

最后的咖啡
装饰器时python语言的魔法,非常非常的灵活,很容易扩展,并且没有耦合。灵活运用装饰器,可以让你的代码更有魔力。不要重复自己,尝试新的挑战,这样才能在编码世界走的更远。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值