知识点

  • 简略的装璜器
  • 带有参数的装璜器
  • 带有自定义参数的装璜器
  • 类装璜器
  • 装璜器嵌套
  • @functools.wrap装璜器应用

根底应用

简略的装璜器

def my_decorator(func):    def wrapper():        print('wrapper of decorator')        func()    return wrapper()def test():    print('test done.')test = my_decorator(test)test输入:wrapper of decoratortest done.

这段代码中,变量test指向了外部函数wrapper(), 而外部函数wrapper()中又会调用原函数test(),因而最初调用test()时,就会打印'wrapper of decorator' 而后输入 'test done.'

这里的函数my_decorator()就是一个装璜器,它把真正须要执行的函数test()包裹在其中,并且扭转了它的行为,然而原函数test()不变。

上述代码在Python中更简略、更优雅的示意:

def my_decorator(func):    def wrapper():        print('wrapper of decorator')        func()    return wrapper()@my_decoratordef test():    print('test done.')test

这里的@, 咱们称为语法糖,@my_decorator就相当于后面的test=my_decorator(test)语句

如果程序中又其余函数须要相似装璜,只须要加上@decorator就能够,进步函数的反复利用和程序可读性

带有参数的装璜器

def args_decorator(func):    def wrapper(*args, **kwargs):        print('wrapper of decorator')        func(*args, **kwargs)    return wrapper@args_decoratordef identity(name, message):    print('identity done.')    print(name, message)identity('changhao', 'hello')输入:wrapper of decoratoridentity done.changhao hello

通常状况下,会把args和*kwargs,作为装璜器外部函数wrapper()的参数。 示意承受任意数量和类型的参数

带有自定义参数的装璜器

定义一个参数,示意装璜器外部函数被执行的次数,能够写成这个模式:

def repeat(num):    def my_decorator(func):        def wrapper(*args, **kwargs):            for i in range(num):                func(*args, **kwargs)        return wrapper    return my_decorator@repeat(3)def showname(message):    print(message)showname('changhao')输入:changhaochanghaochanghao

类装璜器

类也能够作装璜器,类装璜器次要依赖于函数 __call__每当调用一个示例时,函数__call__()就会被执行一次。

class Count:    def __init__(self, func):        self.func = func        self.num_calls = 0    def __call__(self, *args, **kwargs):        self.num_calls += 1        print('num of calls is: {}'.format(self.num_calls))        return self.func(*args, **kwargs)@Countdef example():    print('example done.')example()example()输入:num of calls is: 1example done.num of calls is: 2example done.

这里定义了类Count,初始化时传入原函数func(),而__call__()函数示意让变量num_calls自增1,而后打印,并且调用原函数。因而咱们第一次调用函数example()时,num_calls的值是1,而第一次调用时,值变成了2。

装璜器的嵌套

import functoolsdef my_decorator1(func):    @functools.wraps(func)    def wrapper(*args, **kwargs):        print('execute decorator1')        func(*args, **kwargs)    return wrapperdef my_decorator2(func):    @functools.wraps(func)    def wrapper(*args, **kwargs):        print('execute decorator2')        func(*args, **kwargs)    return wrapper@my_decorator1@my_decorator2def test2(message):    print(message)test2('changhao')输入:execute decorator1execute decorator2changhao

@functools.wrap装璜器应用

import functoolsdef my_decorator(func):    @functools.wraps(func)    def wrapper(*args, **kwargs):        print('wrapper of decorator')        func(*args, **kwargs)        return wrapper@my_decoratordef test3(message):    print(message)test3.__name__  输入test3

通常应用内置的装璜器@functools.wrap,他会保留原函数的元信息(也就是将原函数的元信息,拷贝到对应的装璜器里)

装璜器用法实例

身份认证

import functoolsdef authenticate(func):  @functools.wraps(func)  def wrapper(*args, **kwargs):    request = args[0]    if check_user_logged_in(request):      return func(*args, **kwargs)        else:      raise Exception('Authentication failed')    return wrapper@authenticatedef post_comment(request):  pass

这段代码中,定义了装璜器authenticate;而函数post_comment(),则示意发表用户对某篇文章的评论。每次调用这个函数前,都会检查用户是否处于登录状态,如果是登录状态,则容许这项操作;如果没有登录,则不容许。

日志记录

import timeimport functoolsdef log_execution_time(func):  @functools.wraps(func)  def wrapper(*args, **kwargs):    start = time.perf_counter()    res = func(*args, **kwargs)    end = time.perf_counter()    print('{} took {} ms'.format(func.__name__, (end - start) * 1000))    return wrapper@log_execution_timedef calculate_similarity(times):  pass

这里装璜器log_execution_time记录某个函数的运行工夫,并返回其执行后果。如果你想计算任何函数的执行工夫,在这个函数上方加上@log_execution_time即可。

总结

  • 所谓装璜器,其实就是通过装璜器函数,来批改原函数的一些性能,使得原函数不须要批改。