码迷,mamicode.com
首页 > 其他好文 > 详细

装饰器

时间:2020-06-01 22:19:04      阅读:68      评论:0      收藏:0      [点我收藏+]

标签:port   cstring   turn   本质   简单的   arp   time()   doc   type   

定义

  本质是函数,用来装饰其他函数(为其他函数添加附加功能)。通俗来讲:高阶函数 + 嵌套函数 = 装饰器

原则

  1.不能修改被装饰的函数的源码

  2.函数的调用方式也不能被修改

 

现存在一个函数 foo(),

import time

def foo():
    time.sleep(1)
    print(in foo)

foo()

这时,我希望添加一个新功能:记录 foo() 的运行时间。我可以新建一个嵌套函数来计算函数的运行时间

def timmer(fun):
    start = time.time()
    fun(*args, **kwargs)
    end = time.time()
    print([DEBUG]{}`s running time:{}.format(fun.__name__, end - start))

def foo():
    time.sleep(1)
    print(in foo)

timmer(foo)

这样确实可以实现,但是这样会修改 foo() 函数的调用,实际中这样做是不对的。

为了不修改函数的源码以及函数的调用方式,我们就会用到装饰器

 

 

最简单的装饰器

import time

def timmer(fun):
    def warpper(*args, **kwargs):
        start = time.time()
        fun(*args, **kwargs)
        end = time.time()
        print([DEBUG]{}`s running time:{}.format(fun.__name__, end - start))
    return warpper

@timmer    # 加上语法糖后,相当于在timmer函数中嵌套了foo函数
def foo():
    time.sleep(1)
    print(in foo)

if __name__ == __main__:
    foo()    # 调用方式仍然是 foo()

加上装饰器@timmer后,foo() 等价于 timmer(foo)

 

带参的装饰器

def witharg(arg):    # 在最外层再套一层函数
    def decorator(fun):
        def wrapper(*args, **kwargs):
            print(outer arg: %d % arg)
            fun()
        return wrapper
    return decorator

@witharg(10)
def foo():
    print(in foo)

if __name__ == __main__:
    foo()

 

类装饰器

相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。此外,类装饰器还可以依靠类内部的 __call__ 方法来“装饰”函数。

class C:
    def __init__(self, fun):
        self.fun = fun

    def __call__(self):    # 修改对象状态
        self.fun()
        print(in __call__)

@C    # 类装饰器
def bar():
    print(in bar)

bar()
print(type(bar))    # <class ‘__main__.C‘>

 

装饰器的顺序

@a
@b
@c
def F():
    print(in F)

F()    # 等价于a(b(c(F)))

 

装饰器 @wraps

使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了,比如函数的 docstring 、__name__。

def decorator(fun):
    def wrapper(*args, **kwargs):
        fun()
        print(in decorator)
    return wrapper

@decorator
def foo():
    print(in foo)

foo()
print(foo.__name__)    # foo被装饰器取代,__name__ 变成了 wrapper

为了避免这种情况,python中有 functools.wraps 函数

wraps本身也是个装饰器,它能把原函数的元信息拷贝到装饰器函数中,这使得装饰器函数也有和原函数一样的元信息了。

form functools import wraps
def decorator(fun):
    @wraps(fun)
    def wrapper(*args, **kwargs):
        fun()
        print(in decorator)
    return wrapper

@decorator
def foo():
    print(in foo)

foo()
print(foo.__name__)    # foo

 

装饰器

标签:port   cstring   turn   本质   简单的   arp   time()   doc   type   

原文地址:https://www.cnblogs.com/xiaoqichaoren/p/13027839.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!