python装饰器

2023-10-26

装饰器是python一个重要的部分,由它的名称我们就可以大致了解到它的功能:拓展其他函数。装饰器可以让我们的代码更加简洁,也更加pythonic。

首先,我们先回顾一下基础概念。

、在python中,如果调用一个函数不带括号时,调用的是这个函数本身,无需等待该函数执行完毕;如果调用一个函数带括号时,调用的是这个函数return的结果,需要等待函数执行完毕的结果。实例展示如下:

def demo1():
    print("hello 2022")
demo1()
print(demo1)
#结果依次如下:
#hello 2022
#<function demo1 at 0x015E77C0>

二、函数闭包

闭包就是引用自由变量的函数,这个函数保存了执行的上下文,可以脱离原本的作用于存在。

def dec():
    para = 'closure'

    # 嵌套一层 形成闭包
    def wrapper():
        print(para)
    return wrapper

# 获取一个闭包
closure =  dec()

# 执行
closure()

para是一个局部变量,在dec中执行后即被回收。在嵌套函数中使用了这个变量,也就是将局部para变量封闭在嵌套函数中,形成闭包。

三、python装饰器

介绍了以上基础概念之后,我们再来介绍python装饰器的详细用法。

现在有如下代码:

def func():
    print("hello")
    sleep(5)
    print(2022)

现在需求来了,我们想拓展一下原来的函数,在原有的基础下增加一个计算函数执行时间的模块。

我们首先想到的便是编写一个计时函数,可以直接完成我们的需求。代码如下:

from time import time, sleep
def timer():
    start = time()
    func()
    end = time()
    res = end - start
    print("执行时间为{:.3f}".format(res))
def func():
    print("hello")
    sleep(5)
    print(2022)
if __name__  == "__main__":
    timer()

#执行结果如下
#hello
#2022
#执行时间为5.000

现在我们已经完成了对func()函数执行时间的计算,值得庆幸的是我们现在只有一个函数需要计算它的运行时间,如果一个代码中有成千上万计像func()函数都需要计算他们的运行时间该怎么办?总不能为每一个函数添加一个计时器或者不断地修改timer函数,这样不仅对操作员还是机器都是一个巨大的折磨。这时我们便选用@装饰器来解决我们这些问题。

代码展示如下:

from time import time, sleep
def timer(c):
    print("this is timer")
    def wrapper():
        start = time()
        c()
        end = time()
        res = end - start
        print("执行时间为{:.3f}".format(res))
    return wrapper
@timer
def func():
    print("hello")
    sleep(5)
    print(2022)
if __name__  == "__main__":
    func()
"""
执行结果如下
this is timer
hello
2022
执行时间为5.000
"""

通过对比,我们发现timer函数中增加了wrapper函数,timer函数的返回值是wrapper函数,可以粗暴的理解为timer()=wrapper()。

现在来分析一下以上代码的工作流程:@timer及其一下四行为装载装饰器的过程,装饰器timer的参数是一个函数,返回值也是一个函数,作为参数的函数c()就在闭包函数内执行;在func()前使用@timer,就相当于为func()注入了新的功能,我们既不需要入侵原函数,也不用重复执行原函数。

接下来我们继续分析func()有参数的情况。

代码如下:

from time import time, sleep
def timer(c):
    print("this is timer")
    def wrapper(a, b):
        start = time()
        c(a, b)
        end = time()
        res = end - start
        print("执行时间为{:.3f}".format(res))
    return wrapper
@timer
def func(a, b):
    sleep(5)
    print("a+b=%d" % (a + b))
if __name__ == "__main__":
    func(4, 5)

"""
this is timer
a+b=9
执行时间为5.001
"""

需要注意的是,func()与wrapper()中的参数必须一致。

接下来我们要思考的问题便是:如果func()有无穷多个参数怎么办呢?有没有一个简单的方法可以传递参数?我们想到的是利用位置参数*args和关键字参数**kwargs。(*args与**kwargs的用法不在赘述)具体是怎么实现的呢?我们来看代码。

from time import time, sleep
def timer(c):
    print("this is timer")
    def wrapper(*args, **kwargs):
        start = time()
        c(*args, **kwargs)
        end = time()
        res = end - start
        print("执行时间为{:.3f}".format(res))
    return wrapper
@timer
def func(a, b):
    sleep(2)
    print("a+b=%d" % (a + b))
if __name__ == "__main__":
    func(4, 5)
"""
this is timer
a+b=9
执行时间为2.000

"""

显而易见,我们大大简化了代码。

接下来有两个例子供大家更好的掌握装饰器的用法。

import time
def timer(func):
    print("this is timer")
    def wrapper(*args, **kwargs):
        start = time.time()
        func(*args, **kwargs)
        end = time.time()
        cha_zhi = end - start
        print("运行时间为%d" % cha_zhi)
    return wrapper
def login(func):
    print("this is login")
    def wrapper1(*args, **kwargs):
        user = input("please input your name:")
        password = input("please input your password:")
        if user == 'root' and password == 'root':
            print("login successful!")
            res = func(*args, **kwargs)
            return res
        else:
            print("error!")
    return wrapper1
@login
@timer
def index():
    time.sleep(0.5)
    print("from index")
index()
"""
this is timer
this is login
please input your name:root
please input your password:root
login successful!
from index
运行时间为0
"""
def dec1(func):
    print("1")
    def one():
        print("2")
        func()
        print("3")
    return one
def dec2(func):
    print("a")
    def two():
        print("b")
        func()
        print("c")
    return two
@dec1
@dec2
def test():
    print("test")
test()
"""
a
1
2
b
test
c
3
进程已结束,退出代码为 0

"""

 来看这块代码:当遇到两个装饰器时,执行的顺序是有下往上,即test=dec1(dec2(test)),先执行dec2(test),输出a,此时dec2()中的参数func指向test,返回two(),然后dec1(two), 输出1,dec1()中func指向two,返回one()。test()是实际被装载的函数,此时实际执行的是one(), 运行到func()时再执行two()。

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

python装饰器 的相关文章

随机推荐

  • 余弦定理实现新闻自动分类算法

    前言 余弦定理 这个在初中课本中就出现过的公式 恐怕没有人不知道的吧 但是另外一个概念 可能不是很多的人会听说过 他叫空间向量 一般用e表示 高中课本中有专门讲过这个东西 有了余弦定理和向量空间 我们就可以做许多有意思的事情了 利用余弦定理
  • Spring框架(三)Spring注解和获取Bean对象详解

    目录 一 什么是基于Java的Spring注解配置 具体注解的例子 二 更好的将Bean存储在Spring中 1 前置工作 在配置文件中设置Bean根路径 2 添加注解存储Bean对象 2 1 Controller 控制器存储 2 2 Se
  • Vue中 实现上一篇下一篇的功能

    效果 看下html页面 div class NewsDetails cont footer div img src assets img newsDetail 公共 更多2 1 png alt span 上一篇 lastTitle span
  • 软件开发 文档 质量

    1 在撰写API文档时 如果某个API的性能 时间性能 内存性能 特别低 应该在文档里详细列出 如此做的好处是 1 1 有助于客户在设计阶段 采用正确 高效的方案 1 2 对于开发这个API的team 可以减轻维护压力 明确责任 因为在文档
  • 中文同义句在线转换器 - 中文同义句转换器软件

    在线同义句转换器 中文同义句在线转换器 中文同义句转换器软件 made in Japan 祝你学习进步 更上一层楼 请记得采纳 谢谢 同义句转换器 1 I d like to go to the beach on vacation beca
  • 【1803. 统计异或值在范围内的数对有多少】

    来源 力扣 LeetCode 描述 给你一个整数数组 nums 下标 从 0 开始 计数 以及两个整数 low 和 high 请返回 漂亮数对 的数目 漂亮数对 是一个形如 i j 的数对 其中 0 lt i lt j lt nums le
  • 2019年黑马新版Java学习路线图(内含大纲+视频+工具+书籍+面试)面试必看!

    非常好的java学习路线 伴有配套资源 面试必看 黑马程序员 http bbs itheima com thread 386464 1 1 html
  • LEVELDB介绍

    基本信息 特性 keys 和 values 是任意的字节数组 数据按 key 值排序存储 调用者可以重载函数来重写排序顺序 提供基本的 Put key value Get key Delete key Batch 操作 多个更改可以在一个原
  • JWT

    1 常见的认证机制 1 1 HTTP Basic Auth HTTP Basic Auth简单点说明就是每次请求API时都提供用户的username和password 简言之 Basic Auth是配合RESTful API 使用的最简单的
  • SpringBoot整合Shiro

    一 pom xml引入依赖 1 shiro依赖
  • python3+tkinter实践历程(四)——模仿CRT完成基于socket通信与tkinter的TCP串口客户端

    python3 tkinter实践历程 四 基于socket通信与tkinter的TCP串口客户端 仿CRT 文章目录 系列文章目录 分享背景 制作背景 最终功能 工具截图展示 代码详解 系列文章目录 python3 tkinter实践历程
  • 天龙八部手游服务器维护公告,天龙八部手游更新维护公告 龙腾迎春全新资料片来袭...

    天龙八部手游终于迎来全新资料片 龙腾迎春啦 本次更新将加入全新帮派副本决战少室山 并且玩家们可以觉醒独特的至尊武魂 玩家们可以凭自己的喜好改变武魂的外观 一起来了解一下详细更新内容吧 更新时间 1月31日4 00 8 00 更新奖励 300
  • 查看表被数据库中其他对象使用

    select from dba dependencies where referenced name upper xxx
  • java求六位数以内所有自幂数

    如果在一个固定的进制中 一个n位自然数等于自身各个数位上数字的n次幂之和 则称此数为自幂数 以下用java语言求六位数以内所有自幂数 独身数共有9个 1 2 3 4 5 6 7 8 9 水仙花数共有4个 153 370 371 407 四叶
  • angular.js中的复选框checkbox的用法

    首先在head里引入 页面部分 div div div div
  • RestfulTool插件使用详解

    1 全局搜索 2 提供了一个 Services tree 的API接口显示窗口 右侧会有RestServices侧边栏 点击后会显示当前项目所有请求地址 可以进行输入查询 然后会直接把请求方式 地址以及参数列出来 默认请求服务器为本机 lo
  • 【python】socket-传输多个文件、大文件

    socket 传输多个文件 大文件 0 前言 1 发送单个文件流程 2 关于发送大文件 本地读取时报错 MemoryError 3 关于粘包 问题背景 排错过程 解决方案 4 备注 换算表 0 前言 看过挺多个发文件的例子 但是基本都是发单
  • 每日博客 :>

    1 交换数组 define CRT SECURE NO WARNINGS 1 include
  • 计算机网络34-学习笔记-IP地址

    IP地址属于网络层 这里主要介绍IP地址作用 与MAC地址配合 主机H1将数据包发送给路由器R1 在网络层封装的IP数据报首部中 源IP地址应填写主机H1的IP地址IP1 目的IP地址应填写主机H2的IP地址IP2 在数据链路层中源MAC地
  • python装饰器

    装饰器是python一个重要的部分 由它的名称我们就可以大致了解到它的功能 拓展其他函数 装饰器可以让我们的代码更加简洁 也更加pythonic 首先 我们先回顾一下基础概念 一 在python中 如果调用一个函数不带括号时 调用的是这个函