关于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即可。

总结

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

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理