python 装饰器的基本使用


Posted in Python onJanuary 13, 2021

知识点

  • 简单的装饰器
  • 带有参数的装饰器
  • 带有自定义参数的装饰器
  • 类装饰器
  • 装饰器嵌套
  • @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 相关文章推荐
python发送伪造的arp请求
Jan 09 Python
python在命令行下使用google翻译(带语音)
Jan 16 Python
Python使用ftplib实现简易FTP客户端的方法
Jun 03 Python
剖析Django中模版标签的解析与参数传递
Jul 21 Python
python查看FTP是否能连接成功的方法
Jul 30 Python
利用python实现命令行有道词典的方法示例
Jan 31 Python
代码详解django中数据库设置
Jan 28 Python
对python3 sort sorted 函数的应用详解
Jun 27 Python
pygame实现俄罗斯方块游戏(基础篇1)
Oct 29 Python
Flask框架请求钩子与request请求对象用法实例分析
Nov 07 Python
python 负数取模运算实例
Jun 03 Python
python通过cython加密代码
Dec 11 Python
python日志通过不同的等级打印不同的颜色(示例代码)
Jan 13 #Python
浅谈Selenium+Webdriver 常用的元素定位方式
Jan 13 #Python
Selenium Webdriver元素定位的八种常用方式(小结)
Jan 13 #Python
基于python+selenium自动健康打卡的实现代码
Jan 13 #Python
Python爬虫scrapy框架Cookie池(微博Cookie池)的使用
Jan 13 #Python
matplotlib交互式数据光标实现(mplcursors)
Jan 13 #Python
Python 生成短8位唯一id实战教程
Jan 13 #Python
You might like
php+AJAX传送中文会导致乱码的问题的解决方法
2008/09/08 PHP
生成随机字符串和验证码的类的PHP实例
2013/12/24 PHP
PHP加密解密类实例分析
2015/04/20 PHP
微信公众号判断用户是否已关注php代码解析
2016/06/24 PHP
Symfony2获取web目录绝对路径、相对路径、网址的方法
2016/11/14 PHP
ThinkPHP整合datatables实现服务端分页的示例代码
2018/02/10 PHP
php微信公众号开发之答题连闯三关
2018/10/20 PHP
php设计模式之观察者模式实例详解【星际争霸游戏案例】
2020/03/30 PHP
PHP设计模式(四)原型模式Prototype实例详解【创建型】
2020/05/02 PHP
屏蔽鼠标右键、Ctrl+n、shift+F10、F5刷新、退格键 的javascript代码
2007/04/01 Javascript
js格式化货币数据实现代码
2013/09/04 Javascript
微信小程序 UI与容器组件总结
2017/02/21 Javascript
yii form 表单提交之前JS在提交按钮的验证方法
2017/03/15 Javascript
JavaScript中的普通函数和箭头函数的区别和用法详解
2017/03/21 Javascript
微信小程序实现给循环列表添加点击样式实例
2017/04/26 Javascript
Vue原理剖析 实现双向绑定MVVM
2017/05/03 Javascript
jquery基于layui实现二级联动下拉选择(省份城市选择)
2017/06/20 jQuery
js中this的指向问题归纳总结
2018/11/28 Javascript
Vue使用NProgress进度条的方法
2019/09/21 Javascript
微信小程序 自定义弹窗实现过程(附代码)
2019/12/05 Javascript
[48:52]DOTA2上海特级锦标赛A组小组赛#2 Secret VS CDEC第一局
2016/02/25 DOTA
python中将zip压缩包转为gz.tar的方法
2018/10/18 Python
Pytorch实现基于CharRNN的文本分类与生成示例
2020/01/08 Python
Python爬虫库BeautifulSoup获取对象(标签)名,属性,内容,注释
2020/01/25 Python
python操作docx写入内容,并控制文本的字体颜色
2020/02/13 Python
Python super()函数使用及多重继承
2020/05/06 Python
解决keras,val_categorical_accuracy:,0.0000e+00问题
2020/07/02 Python
世界上最大的餐具公司:Oneida
2016/12/17 全球购物
欧铁通票官方在线销售网站:Eurail.com
2017/10/14 全球购物
Orlebar Brown官网:设计师泳裤和泳装
2020/12/08 全球购物
新加坡最早生产电动滑板车的制造商之一:FunsToTheFore
2020/09/08 全球购物
初中生学习的自我评价
2013/11/14 职场文书
公益广告语集锦
2014/03/13 职场文书
会议欢迎词范文
2015/01/27 职场文书
四年级语文教学反思
2016/03/03 职场文书
详解MySQL的半同步
2021/04/22 MySQL