python 装饰器的基本使用

 更新时间:2021年01月13日 10:20:38   作者:changhao  
这篇文章主要介绍了python 装饰器的基本使用,帮助大家更好的理解和使用python,感兴趣的朋友可以了解下

知识点

  • 简单的装饰器
  • 带有参数的装饰器
  • 带有自定义参数的装饰器
  • 类装饰器
  • 装饰器嵌套
  • @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

类装饰器

类也可以作装饰器,类装饰器主要依赖于函数 __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即可。

总结

所谓装饰器,其实就是通过装饰器函数,来修改原函数的一些功能,使得原函数不需要修改。

以上就是python 装饰器的基本使用的详细内容,更多关于python 装饰器的资料请关注脚本之家其它相关文章!

相关文章

  • Python中yield关键字及与return的区别详解

    Python中yield关键字及与return的区别详解

    这篇文章主要介绍了Python中yield关键字及与return的区别详解,带有 yield 的函数在 Python 中被称之为 generator生成器,比如列表所有数据都在内存中,如果有海量数据的话将会非常耗内存,想要得到庞大的数据,又想让它占用空间少,那就用生成器,需要的朋友可以参考下
    2023-08-08
  • Python numpy生成矩阵、串联矩阵代码分享

    Python numpy生成矩阵、串联矩阵代码分享

    这篇文章主要介绍了Python numpy生成矩阵、串联矩阵代码分享,具有一定参考价值,需要的朋友可以了解下。
    2017-12-12
  • 基于 Django 的手机管理系统实现过程详解

    基于 Django 的手机管理系统实现过程详解

    这篇文章主要介绍了基于 Django 的手机管理系统过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • Python turtle库(绘制螺旋正方形)

    Python turtle库(绘制螺旋正方形)

    这篇文章主要介绍了Python turtle库(绘制螺旋正方形),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • Python安装Talib库的详细图文教程

    Python安装Talib库的详细图文教程

    talib库的安装之路坑特别多,这是最常见的,下面这篇文章主要给大家介绍了关于Python安装Talib库的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2022-12-12
  • Python的collections模块真的很好用

    Python的collections模块真的很好用

    collections是实现了特定目标的容器,以提供Python标准内建容器 dict , list , set , 和 tuple 的替代选择,本文详细总结collections的相关知识,感兴趣的朋友跟随看看吧
    2021-03-03
  • Python保存dict字典类型数据到Mysql并自动创建表与列

    Python保存dict字典类型数据到Mysql并自动创建表与列

    这篇文章主要介绍了Python保存dict字典类型数据到Mysql并自动创建表与列,字典是另一种可变容器模型,且可存储任意类型对象,想了解更多内容的小伙伴可以和小编一起进入下面文章学习更多内容,希望对你有所帮助
    2022-02-02
  • python requests模块的使用示例

    python requests模块的使用示例

    这篇文章主要介绍了python requests模块的使用解析,帮助大家更好的理解和学习使用python,感兴趣的朋友可以了解下
    2021-04-04
  • 用python写扫雷游戏实例代码分享

    用python写扫雷游戏实例代码分享

    我们给大家分享了一篇关于用python写一个扫雷经典游戏的实例代码,大家可以测试运行下。
    2018-05-05
  • Pycharm调试程序技巧小结

    Pycharm调试程序技巧小结

    这篇文章主要介绍了Pycharm调试程序技巧,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08

最新评论