python 带参装饰器_python带参数的装饰器

2023-05-16

装饰器更高级的用法是可以带参数。

带参数的装饰器

先来看一个不带参数的装饰器

1

2

3

4

5

6

7

8

9

10

11

12

13

14import time

def timeit(fn):

def wrap(*args,**kwargs):

start = time.time()

ret = fn(*args,**kwargs)

print(time.time() - start)

return ret

return wrap

@timeit

def sleep(x):

time.sleep(x)

1sleep(3)

3.0034420490264893

这里打印出来的是执行sleep函数所消耗的自然时间,但在执行此函数时所消耗的cpu时间真的有3.0034420490264893秒吗?当然不是。利用time包中的time.clock方法可以计算得到代码执行所消耗cpu的时间,那怎样来修改上边的timeit函数,让其即能计算代码执行的自然时间,也能计算代码执行所消耗cpu的时间?做如下改进:

1

2

3

4

5

6

7

8

9

10

11

12

13def timeit_1(process_time=False):

cacl = time.clock if process_time else time.time

def timeit_2(fn):

def wrap(*args,**kwargs):

start = cacl()

ret = fn(*args,**kwargs)

print(cacl() - start)

return ret

return wrap

return timeit_2

def sleep_1(x):

time.sleep(x)

1timeit_1(True)(sleep_1)(3)

0.020000000000000018

1timeit_1(False)(sleep_1)(3)

3.0038363933563232

1timeit_1()(sleep_1)(3) # 参数process_time是一个默认参数,所以可以不传递值,默认为False

3.003509283065796

上边的调用过程是怎样的呢?分解一下,如下:

1fn1 = timeit_1(True)

上边调用timeit_1(True),函数return回了timeit_2,并把fn1这个变量指向了调用结果,即指向了timeit_2,这里的timeit_2也是一个函数,此函数接收一个参数

1fn2 = fn1(sleep_1)

这里调用fn1(sleep_1),其实就是调用了timeit_2(sleep_1),并把fn2这个变量指向了调用后的结果,即指向了warp,这里的warp也是一个函数,此函数能接收任意的参数

1fn2(3)

0.009999999999999787

上边调用fn2(3),其实是调用了wrap(3),即执行了wrap函数内的语句,此函数内的ret = fn(*args,**kwargs)语句中的fn其实是指向了sleep,所以在执行wrap函数时,sleep_1函数才真正被执行。

既然装饰器可以用魔法来装饰一个函数,那上边经过改进过的装饰器是不是也能装饰一个函数呢?如下:

1

2

3@timeit_1(False)

def sleep_2(x):

time.sleep(x)

1sleep_2(3)

3.0039477348327637

如果想计算代码执行的cpu时间,那如下即可:

1

2

3@timeit_1(True)

def sleep_3(x):

time.sleep(x)

1sleep_3(3)

0.0

这个魔法又发生了什么呢?

其实质就是在没有用魔法的情况下直接timeit_1(True)(sleep_3)(3)。而当使用@这个魔法后,当代码执行到此行时,解析器会执行timeit_1(True),timeit_1实质就是一函数,接收一个参数,并返回一个timeit_2函数。当代码执行到@所在语句时,会把所装饰的sleep_3函数作为一个参数传递给timeit_1(True)的调用结果,即timeit_2这个函数,即sleep_3这个函数已作为一个变量传递给了timeit_2(fn)中的fn参数,并返回了一个wrap函数,在接下的调用sleep_3(3)这个操作,其实此时的sleep_3这个函数已不是原先的def sleep_3(x):中的sleep_3函数,而是一个指向了wrap的函数,wrap函数接收任何参数,所以把当执行sleep_3(3)时,把参数3传递给了wrap函数,并执行内部的代码,内部代码中ret = fn(*args,**kwargs)中的fn函数依赖还是指向原先的sleep_3(x)这个函数。

这里也有一个简单的记忆方式,如果一个函数被装饰器所装饰,在调用这个函数时其实不再是调用表面上看上去的这个函数,以

1

2

3@timeit_1(True)

def sleep_3(x):

time.sleep(x)

来做说明。当执行到有@魔法所在行时,相当于执行了sleep_3 = timeit_1(True)(sleep_3),即指向了wrap函数,既然sleep_3指向了wrap函数,那我们执行sleep_3(3)时,其实就是在进行wrap(3)这样的函数调用,记住,函数名也是一个变量。

再来举一个带参数的装饰器的例子,比如有一个函数,只有在对有许可权限的用户开放,执行此函数的用户没有在认证列表里的,就不会执行这个函数。这个该如何实现呢?如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14def check(allow_users):

def inner_check(fn):

def wrap(username,*args,**kwargs):

'''This is wrap'''

if username in allow_users:

return fn(username,*args,**kwargs)

return "You are illegal users"

return wrap

return inner_check

@check(['zhaochj','zcj'])

def private(username):

'''The authentication'''

return "You are legitimate users"

1private('zhaochj')

'You are legitimate users'

1private('tom')

'You are illegal users'

这样就可以对调用函数进行身份验证。

python中一个函数有一些属性是函数本身具有的,比如__name__属性是查看函数名称,__doc__是查看函数文档的等等。如果一个函数被装饰器装饰过后,这个函数的这些属性会发生怎样的变化呢?以上边的check装饰器和private函数为例子,如下:

1private.__name__

'wrap'

1private.__doc__

'This is wrap'

private函数的名称是wrap了,文档也是wrap函数的文档,这是怎么回事?上边已经说过,这里的private函数被装饰器装饰后它已不再是原来的private函数,private这个函数名称会被指向到wrap这个函数对象,那当然用上边的private.__name__和private.__doc__查看函数的属性就会是wrap函数的属性。那怎样来修正呢?可以这样做,如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17def check_1(allow_users):

def inner_check(fn):

def wrap(username,*args,**kwargs):

'''This is wrap'''

if username in allow_users:

return fn(username,*args,**kwargs)

return "You are illegal users"

wrap.__name__ = fn.__name__

wrap.__doc__ = fn.__doc__

return wrap

return inner_check

@check_1(['zhaochj','zcj'])

def private_1(username):

'''The authentication'''

return "You are legitimate users"

1private_1.__name__

'private_1'

1private_1.__doc__

'The authentication'

通过在装饰器把__name__和__doc__重新赋值后就能更正这个问题,但对一个函数来说像__name__这样类似的属性有许多,如果都是这样手工来修正显然是不现实的,所以python提供了一个wraps装饰器来自动修正这个问题,wraps在functools这个包中,所以可以这样来修正这个问题,如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18import functools

def check_1(allow_users):

def inner_check(fn):

@functools.wraps(fn)

def wrap(username,*args,**kwargs):

'''This is wrap'''

if username in allow_users:

return fn(username,*args,**kwargs)

return "You are illegal users"

return wrap

return inner_check

@check_1(['zhaochj','zcj'])

def private_1(username):

'''The authentication'''

return "You are legitimate users"

1private_1.__name__

'private_1'

1private_1.__doc__

'The authentication'

@functools.wraps(fn)这个装饰器相当于执行了wrap.__name__ = fn.__name__这样的操作。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python 带参装饰器_python带参数的装饰器 的相关文章

  • [PyQt5]点击主窗口弹出另一个窗口

    1 先使用Qt designer设计两个窗口 xff0c 一个是主窗口 xff0c 一个是子窗口 其中主窗口是新建 Main Window 子窗口是Dialog窗体 两个窗口不能是同一类型 否则会崩溃 并保存为EyeTracking mai
  • matlab的for循环

    https blog csdn net zhyoulun article details 78606382
  • 【总结】自然语言处理(NLP)算法:概述与分类

    摘要 xff1a NLP概述 主要参考自然语言处理 xff08 NLP xff09 知识结构总结和知乎上的一些问答 目录 NLP界神级人物NLP知识结构 1 概述2 形式语言与自动机3 语言模型4 概率图模型 xff0c 生成模型与判别模型
  • 【Win10】【开始菜单打不开】任务栏修复

    真是 xff0c 朋友说一句 xff0c 电脑出问题了你有本事别重装系统 我记住了 作为一个 强迫症患者 xff0c 最近电脑C盘内存快满以及翻墙代理污染了一部分ipv4网站就让我很毛 xff0c 很想重装系统 但是我忍住了 根据网上的教程
  • 「PyQt5」使用Qtdesigner设计好界面后写一个驱动程序

    使用Python写界面最方便的就是Pycharm 43 Qtdesigner 用Qt designer画用户界面比较容易 xff0c 保存成 ui文件然后转化成 py即可 这里 xff0c 我们展示下一步运行程序让这个界面显示 xff1a
  • 「git」Linux下将文件都上传到github上

    最近在整理自己平时写的一些代码 xff0c 第一选择就是上传到github上作为一个备份和说明 xff0c 防止自己遗忘 上次用版本控制已经是好几个月前了 xff0c 所以难免有些生疏 所以就从新按照CSDN大佬们的基础教程重新操作了一遍
  • 高质量嵌入式Linuxc编程

    第一天 xff1a 根目录 命令 注意 xff1a 命令和参数要区分开 xff0c 他们之间要有空格 cd 进入目录 ls 列举目录内容 ls a 列举所有文件包括隐藏的文件 所有隐藏的文件都是以点 xff08 xff09 开始的 ls l
  • 读写位宽不同的FIFO,数据输入输出顺序是怎么样的?BRAM又如何呢?

    原文地址 xff1a https wenku baidu com view 7d7cf156284ac850ac0242b6 html 对于BRAM xff1a 1 xff09 写位宽小于读位宽 xff1a 先入存低位 xff0c 后入存高
  • apache httpd在centos上手动安装

    Apache Bench手动安装 简介httpd及依赖包安装ab扩充最大并发量 简介 apache bench简称 xff08 ab xff09 可以做压力测试 xff0c 本文介绍手动安装方法 httpd及依赖包安装 以下包因为存在依赖关
  • Cartographer最新版完整安装教程(2020.8.7成功安装)

    2020 8 7更 xff1a 春节之后重装了系统 xff0c 重新安装Cartographer又遇到了困难 xff0c 发现之前的教程naive xff0c 历尽千辛万苦今天终于安装成功 xff0c 而且更加简单方便 xff0c 给大家作
  • 没有可用的软件包××,但是它被其他的软件包引用了——解决方法

    在ubuntu下安装gcc xff1a sudo apt install gcc 谁知这么简单的命令居然不成功 解决方法 xff1a sudo apt get update 待更新完毕后再次输入安装命令即可
  • MapReduce编程之连接Join

    本文笔记整理自 Hadoop海量数据处理 xff1a 技术详解与项目实战 范东来 一 设计思路 HDFS上存放两个文件 xff0c 一个记录了学生基本信息 xff08 姓名 xff0c 学号 xff09 xff0c 文件名 student
  • MapReduce编程之二次排序

    本文笔记整理自 Hadoop海量数据处理 xff1a 技术详解与项目实战 范东来 一 二次排序 二次排序就是先按某一列先进行排序 xff0c 然后在此基础上再对另一列排序 xff08 参看如下表数据 xff09 待排序数据 xff1a 第一
  • 接口测试 之 HTTP 1.1 认证之BASIC认证

    basic认证 介绍认证步骤步骤图解BASIC 认证的的缺点测试 xff1a 认证失败测试 xff1a 认证成功使用postman 如何测试basic认证接口 介绍 BASIC 认证 xff08 基本认证 xff09 是从HTTP 1 1
  • PX4仿真基础

    本文章描述jmavsim和gazebo两种仿真器的使用 仿真器可以让PX4飞行控制程序在仿真的 世界 中控制一架计算机模拟的飞行器 您可以使用QGroundControl地面站程序 API或遥控器与该飞行器进行交互 xff0c 就像与真实飞
  • 在PX4-JMAVSIM软件仿真环境下运行树梅派上的Dronekit飞控应用程序

    苍穹四轴DIY 微信公众号培训教材对Pixhawk飞机加装Raspberry Pi做了介绍 xff0c 关于软件仿真 xff0c 介绍了在Ardupilot飞控系统软件仿真下运行树梅派上的飞控应用程序 xff0c 此文介绍的是在PX4飞控系
  • 在ubuntu上通过编译源代码生成并安装MAVSDK-C++

    版本说明 xff1a ubuntu server 20 0 04 MAVSDK 1 3 1 PX4官网通过编译源代码安装MAVSDK的文章如下 xff1a Building library from Source MAVSDK Guide
  • 在PX4中如何使用offboard模式以及对c_uart_interface_example程序的分析

    c uart interface example是mavlink团队提供的一个演示如何用c语言调用mavlink API对飞机做offboard控制的例子程序 xff0c 这个程序写的挺漂亮的 xff0c 但是 xff0c 新的固件 xff
  • MAVSDK(c++) takeoff_and_land程序分析

    MAVSDK xff08 c 43 43 takeoff and land程序分析 takeoff and land程序是用c 43 43 语言调用MAVSDK API做起飞和降落的控制 MAVSDK xff08 C 43 43 xff09
  • Ubuntu下安装vmware虚拟机软件,vmware上虚拟机的安装、删除

    一直听说虚拟机虚拟机虚拟机 xff0c 关于具体是什么还是不清楚 纸上觉来终觉浅 xff0c 得知此事要躬行 心里的想法千千万 xff0c 只有写下来才能有落地的实感 百科上查找的资料 xff0c 虚拟机 xff08 Virtial Mac

随机推荐

  • 实现Pixhawk 的PX4系统终端

    版本说明 xff1a 1 自驾仪 xff1a Holybro的Pixhawk 4 2 PX4版本 xff1a 1 13 3 宿主机 xff1a Thinkpad笔记本 43 Ubuntu 20 04 2 LTS 参考 xff1a PX4 C
  • QGC开发环境搭建(欢迎交流学习)

    xff10 xff0f 准备好给各位的文件包 xff1a xff11 xff0f 安装QT 链接 xff1a https pan baidu com s 1LvZ7FkDRtHSBFE7YLLBqfw 提取码 xff1a 9kin xff1
  • 四旋翼无人机物理基础

    四旋翼无人机物理基础 1 结构形式2 运动原理 垂直运动 俯仰运动 滚转运动 xff1a 偏航运动 xff1a 前后运动 xff1a 倾向运动 xff1a 1 结构形式 旋翼对称分布在机体的前后 左右四个方向 xff0c 四个旋翼处于同一高
  • npm 清理缓存命令

    npm cache clean f 有些时候npm下载资源出错 xff0c 再次下载的时候可能因为之前错误的缓存造成一直下载不成功 此时可以清一下npm的缓存 xff0c 然后尝试重新下载 使用 可以多清理几次 npm cache clea
  • Taro 和 uni-app选型对比

    Taro 和 uni app选型对比 一 Taro和uni app的介绍 1 taro的介绍 taro是多端统一开发框架 xff0c 支持用 React 的开发方式编写一次代码 xff0c 生成能运行在微信 百度 支付宝 字节跳动小程序 H
  • 小程序 连接websocket 开发者工具上可以,但是真机上不行

    连接websocket 开发者工具上可以 xff0c 但是真机上不行 一定要保证真机和websocket机器在同一个网段 xff1b 基础库 2 4 0 提供了 wx startLocalServiceDiscovery 等一系列 mDNS
  • JS filter()方法 介绍和使用

    filter方法是js中常用的方法 xff1b 一 xff0c 作用 xff1b filter用于对数组进行过滤 它创建一个新数组 xff0c 新数组中的元素是通过检查指定数组中符合条件的所有元素 注意 xff1a filter 不会对空数
  • JS object对象转为array数组

    在开发中经常会遇到接口返回的是对象 xff0c 我们需要转为数组 xff0c 下面提供两种方法 xff1a 第一种方法 xff0c Object values span class token keyword var span data s
  • JS关闭当前页面

    JS关闭当前页面 span class token operator lt span button onclick span class token operator 61 span span class token string 34 C
  • 【马井堂】Js 去掉对象前后空格

    Js 去掉对象前后空格 function emptyParams data const temporary 61 Object assign data for const key in temporary if key if tempora
  • VMware 虚拟机与主机通信三种方式总结

    背景 xff1a ubuntu16 04安装vmware14pro xff0c 开了两台ubuntu12 04的虚拟机 第一台基于NAT方式连接 xff0c 第二台基于Bridged方式连接 主机IP xff1a 192 168 100 1
  • JS 下载-支持多个浏览器(马井堂)

    JS 下载 支持多个浏览器 const downLoadXls 61 fileArrayBuffer filename 61 gt let data 61 new Blob fileArrayBuffer type 39 applicati
  • js微信小程序-版本更新管理器wx.getUpdateManager()、UpdateManager

    js微信小程序 版本更新管理器wx getUpdateManager UpdateManager 1 wx getUpdateManager 官方文档 版本更新管理器wx getUpdateManager 官方文档 wx getUpdate
  • 串口通信+TCP网络通信简单综合实例

    串口通信 43 TCP网络通信简单综合实例 串口通信加上TCP网络通信之后就可以简单实现本地设备的联网功能了 xff0c 哈哈 xff0c 话不多说 xff0c 直接上代码 总体上还是C S模式 xff0c 但是这个客户端加上了对串口的操作
  • Java设计模式(八)过滤器模式

    一 概要 过滤器模式是一种结构型设计模式 xff0c 它允许通过一系列条件来筛选对象 xff0c 并提供一种灵活的方式来组合和操作这些条件 过滤器模式将过滤条件封装成独立的过滤器类 xff0c 然后使用这些过滤器来过滤对象集合 xff0c
  • 基于ROS的STDR仿真模拟的介绍和使用

    STDR仿真介绍 stdr robot 包实现了模拟机器人 和所有的模拟传感器以及运动控制器 到目前为止 实现了以下传感器 激光雷达 提供了 sensor msgs LaserScan消息类型 超声波传感器 提供sensor msgs Ra
  • docker 删除所有未启动的容器_Docker容器的创建、启动、和停止

    1 容器是独立运行的一个或一组应用 xff0c 及他们的运行环境 容器是Docker中的一个重要的概念 2 docker容器的启动有三种方式 a 交互方式 xff0c 基于镜像新建容器并启动 例如我们可以启动一个容器 xff0c 打印出当前
  • 使用了withoutoverlapping进程还是有多个_进程和线程

    一 进程和线程基本概念 进程 进程是程序的一次执行过程 xff0c 是一个动态概念 xff0c 是程序在执行过程中分配和管理资源的基本单位 xff0c 每一个进程都有一个自己的地址空间 xff0c 至少有 5 种基本状态 xff0c 它们是
  • 查看mysql主从命令_MYSQL主从同步的管理

    这里介绍一些管理MYSQL主从同步的命令 xff1a 1 停止MYSQL同步 STOP SLAVE IO THREAD 停止IO进程 STOP SLAVE SQL THREAD 停止SQL进程 STOP SLAVE 停止IO和SQL进程 2
  • python 带参装饰器_python带参数的装饰器

    装饰器更高级的用法是可以带参数 带参数的装饰器 先来看一个不带参数的装饰器 1 2 3 4 5 6 7 8 9 10 11 12 13 14import time def timeit fn def wrap args kwargs sta