乐趣区

关于python:python3装饰器基础使用

知识点

  • 简略的装璜器
  • 带有参数的装璜器
  • 带有自定义参数的装璜器
  • 类装璜器
  • 装璜器嵌套
  • @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 decorator
test 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_decorator
def 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_decorator
def identity(name, message):
    print('identity done.')
    print(name, message)

identity('changhao', 'hello')

输入:wrapper of decorator
identity 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')

输入:changhao
changhao
changhao

类装璜器

类也能够作装璜器,类装璜器次要依赖于函数 __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)


@Count
def example():
    print('example done.')

example()
example()

输入:num of calls is: 1
example done.
num of calls is: 2
example done.

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

装璜器的嵌套

import functools
def my_decorator1(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print('execute decorator1')
        func(*args, **kwargs)
    return wrapper


def my_decorator2(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print('execute decorator2')
        func(*args, **kwargs)
    return wrapper


@my_decorator1
@my_decorator2
def test2(message):
    print(message)


test2('changhao')

输入:execute decorator1
execute decorator2
changhao

@functools.wrap 装璜器应用

import functools
def my_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print('wrapper of decorator')
        func(*args, **kwargs)
        return wrapper

@my_decorator
def test3(message):
    print(message)

test3.__name__  

输入
test3

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

装璜器用法实例

身份认证

import functools

def 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

@authenticate
def post_comment(request):
  pass

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

日志记录

import time
import functools

def 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_time
def calculate_similarity(times):
  pass

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

总结

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