Python装饰器(一次搞清楚)

这篇具有很好参考价值的文章主要介绍了Python装饰器(一次搞清楚)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

最重要的情绪管理是要明白,没有一种情绪是不应该的

一、简单装饰器

Python装饰器是一种语法糖,用于在不改变原有函数代码的情况下,为函数添加额外的功能。装饰器本质上是一个函数,它接收一个函数作为参数,并返回一个新的函数,通常使用@语法糖来应用装饰器。
1.装饰器本质是一个函数,可称之为函数装饰器;
2.装饰器也是一个闭包,即在非全局范围内定义的函数可以引用其外围空间中的变量
3.装饰器以一个函数作为参数,并且返回值也是一个函数;
4.装饰器不能修改被装饰的函数代码;不能修改被装饰函数的调用方式;
下面是一个简单的装饰器示例:

def my_decorator(func):
    def wrapper():
        print("Before the function is called.")
        res = func()
        print("After the function is called.")
        return res
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

# 调用被装饰的函数
say_hello()

在这个示例中,my_decorator是一个装饰器函数,它接收一个函数作为参数,并返回一个新的函数wrapper。wrapper函数包裹了原有的函数,它在调用原有函数之前和之后打印了额外的信息。@my_decorator语法糖将say_hello函数传递给my_decorator,并将其返回的新函数wrapper赋值给say_hello,这样调用say_hello函数时,实际上是调用了wrapper函数。执行结果为:
Python装饰器(一次搞清楚)

二、装饰器的运用场景

装饰器的应用非常广泛,可以用于实现各种功能,例如:

  1. 记录函数执行时间:通过在装饰器函数中记录函数执行的开始和结束时间,可以计算函数的执行时间。
  2. 缓存函数结果:通过在装饰器函数中维护一个缓存,可以避免重复计算相同参数的函数结果,提高函数的执行效率。
  3. 实现权限控制:通过在装饰器函数中检查用户的权限,可以控制用户对某些函数的访问权限。
  4. 日志记录:通过在装饰器函数中记录函数的输入参数和返回值,可以方便地进行调试和错误排除。
  5. 错误处理:通过在装饰器函数中捕获异常并进行处理,可以避免函数抛出异常导致程序崩溃。

Python装饰器是一种非常强大的语法糖,可以帮助我们实现各种功能,提高代码的复用性和可维护性。

三、运用案列

案列一:Python缓存cache实现

Python中的缓存(cache)机制可以通过装饰器来实现,但并不是所有的缓存都是通过装饰器实现的。装饰器是一种常用的实现缓存的方式,但是Python中还有其他的缓存实现方式,例如使用字典、使用缓存库等。
使用装饰器实现缓存的原理是,在装饰器函数中维护一个字典,将函数的输入参数作为键,函数的返回值作为值,存储在字典中。在每次调用函数之前,先检查字典中是否已经存在相同输入参数的缓存结果,如果存在,则直接返回缓存结果,否则调用原函数计算结果,并将计算结果缓存到字典中。
下面是一个简单的装饰器缓存示例:

def cache(func):
    cached_results = {}
    def wrapper(*args):
        if args in cached_results:
            return cached_results[args]
        result = func(*args)
        cached_results[args] = result
        return result
    return wrapper

@cache
def fibonacci(n):
    if n <= 1:
        return n    
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(10))

1.在这个示例中,cache是一个装饰器函数,它接收一个函数作为参数,并返回一个新的函数wrapper。wrapper函数维护了一个cached_results字典,用于存储函数的缓存结果。在调用被装饰的函数之前,wrapper函数先检查输入参数args是否已经存在于cached_results中,如果存在,则直接返回缓存结果,否则调用原函数计算结果,并将结果存储到cached_results中。
2.这个装饰器可以用于缓存计算复杂的函数,例如计算斐波那契数列的函数fibonacci。在第一次调用fibonacci(10)时,由于没有缓存结果,需要进行计算,计算结果存储到字典中。在后续的调用中,只需要从字典中获取结果即可,避免了重复计算,提高了程序的执行效率。
3.需要注意的是,装饰器缓存的实现方式可能存在一些问题,例如缓存数据的过期问题、内存占用问题等。因此,在实际使用中需要根据具体情况进行选择和调整,以确保程序的正确性和性能。

案列二:打印函数执行时间消耗

import time
# 注意:这个是带参数的装饰器
def calculate_execution_time(unit='s'):
    def decorator(func):
        def wrapper(*args, **kwargs):
            start_time = time.time()
            result = func(*args, **kwargs)
            end_time = time.time()
            execution_time = end_time - start_time
            if unit == 'ms':
                execution_time *= 1000
                print(f"函数 {func.__name__} 的执行时间为: {execution_time:.2f} 毫秒")
            else:
                print(f"函数 {func.__name__} 的执行时间为: {execution_time:.2f} 秒")
            return result
        return wrapper
    return decorator

@calculate_execution_time(unit='ms')
def my_function(a, b):
    # 假设这里是一个耗时的操作
    time.sleep(1)
    # 被装饰函数本身的功能
    print("{0} + {1} = ".format(a, b), a+b)

my_function(1, 2)

1.上述代码定义了一个名为calculate_execution_time的装饰器,它接受一个可选的参数unit,用于指定执行时间的单位,默认为秒。装饰器内部定义了另一个函数decorator,它接受被装饰的函数func作为参数。在wrapper函数中,我们首先记录函数执行开始的时间戳start_time,然后调用被装饰的函数并获取其返回值result,最后计算函数执行所花费的时间,并根据unit参数选择合适的单位进行打印。
2.执行结果:
Python装饰器(一次搞清楚)
3.带参数的装饰器详见下文。

四、带参数的装饰器

Python装饰器可以用于装饰任何可调用对象,包括函数和类。当装饰函数带参数时,需要在装饰器函数里再定义一层函数来接收参数,这样才能将参数传递给被装饰的函数。
下面是一个简单的装饰器示例,演示了如何在装饰器函数中处理带参数的函数:

from functools import wraps
def repeat(num):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for i in range(num):
                print(f"Running function {func.__name__} for the {i+1} time")
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(3)
def greet(name):
    print(f"Hello, {name}!")

greet("John")

1.在这个示例中,repeat是一个装饰器函数,它接收一个参数num,用于指定函数重复执行的次数。decorator是repeat的内部函数,它接收一个函数func作为参数,并返回一个新的函数wrapper。wrapper函数实现了函数的重复执行功能,它在循环中调用被装饰的函数func,并打印执行次数的信息。
另外,@wraps(func)用于保存函数的元信息,例如函数名、参数、注释等,可以使用functools模块中的wraps装饰器来保存被装饰函数的原信息。
2.wraps装饰器实际上是一个装饰器工厂函数,它接收一个函数作为参数,并返回一个新的装饰器函数。这个新的装饰器函数会将被装饰的函数替换为自己,并使用functools模块中的update_wrapper函数来将被装饰函数的元信息复制到新的装饰器函数中。
3.如果不使用wraps装饰器来保存被装饰函数的元信息,那么被装饰函数的元信息会被覆盖,例如函数名会变成wrapper,函数注释会变成装饰器函数的注释。
4.在应用装饰器时,使用@语法糖将装饰器函数repeat(3)应用到函数greet上,例如:

@repeat(3)
def greet(name):
    print(f"Hello, {name}!")

这样,每次调用greet函数时,都会执行3次,打印出执行的次数和函数的输出结果。
5.需要注意的是,在装饰器函数中定义的参数,需要在装饰器的每一层函数中进行传递和处理。在这个示例中,num参数在repeat函数中定义,被传递给decorator函数,最终在wrapper函数中使用。被装饰的函数的参数,需要在wrapper函数中定义为*args**kwargs,以支持任意数量和类型的参数,并在调用被装饰的函数时传递给它。
6.执行结果:
Python装饰器(一次搞清楚)

五、装饰器执行过程

像上面的函数,在代码执行时,会首先将**@cache**加载(函数定义时),执行cache中的内容,不执行wrapper的内容(函数调用时)。后续fibonacci函数执行时,会先执行对应的wrapper的内容,再执行函数本身,即cache中的cached_results类似于wrapper的全局变量
Python装饰器(一次搞清楚)
后续的多次调用中,cache中仅wrapper的内容在执行
Python装饰器(一次搞清楚)

六、装饰器的执行顺序

说法一:装饰顺序按由下到上,调用时由上到下执行顺序和装饰顺序相反。(简单记成正常的代码顺序即可)
说法二:装饰器由下到上依次立马执行,之后我们调用的f已经是被装饰器执行了之后的f了,此时是由上到下返回去依次调用。整个过程有点像先上楼梯(装饰过程),再下楼梯(调用函数)

def decorator_a(func):
    print('Get in decorator_a')
    def inner_a(*args, **kwargs):
        print('Get in inner_a')
        return func(*args, **kwargs)
    return inner_a

def decorator_b(func):
    print('Get in decorator_b')
    def inner_b(*args, **kwargs):
        print('Get in inner_b')
        return func(*args, **kwargs)
    return inner_b

@decorator_b
@decorator_a
def f(x):
    print('Get in f')
    return x * 2

f(1)

执行结果:
Python装饰器(一次搞清楚)
关于执行顺序可参考:https://segmentfault.com/a/1190000007837364文章来源地址https://www.toymoban.com/news/detail-710696.html

到了这里,关于Python装饰器(一次搞清楚)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 情绪管理与AI:未来的人机互动

    情绪管理与AI是一种人工智能技术,它旨在帮助人们更好地理解、管理和调节自己的情绪。随着人工智能技术的不断发展,情绪管理与AI已经成为了未来的人机互动领域中的一个重要话题。在这篇文章中,我们将讨论情绪管理与AI的核心概念、算法原理、具体实例以及未来的发

    2024年02月21日
    浏览(22)
  • 学生成绩管理系统(逻辑清楚-简单实用)

    1.1、需求分析概述 需求分析是我们在软件开发中的重要环节,是软件开发的第一步也是最基础的环节,这将决定我们所实现的目标以及系统的各个组成部分、各部分的任务职能、以及使用到的数据结构、各个部门之间的组成关系和数据流程,为我们的系统设计打下基础。 1

    2024年02月09日
    浏览(43)
  • Python 变量?对象?引用?赋值?一个例子解释清楚

    哈喽大家好,我是咸鱼。 前天有个小伙伴找到我,给了我一段 python 代码: 然后问我为什么结果是 [1, [...]] ,我一看这个问题有意思,我说三言两语解释不清楚,我写篇文章到时候你看下吧,于是有了今天这篇文章。 在正式开始之前,让我们先弄清楚一些概念。 \\\"Python 中一

    2024年01月24日
    浏览(46)
  • 一文梳理清楚 Python OpenCV 的知识体系

    本篇文章为你详细罗列 Python OpenCV 的学习路线与重要知识点。核心分成 24 个小节点,全部掌握,OpenCV 入门阶段就顺利通过了。 本部分要了解 OpenCV (Open Source Computer Vision Library)的相关简介,OpenCv 可以运行在多平台之上,轻量级而且高效,由一系列 C 函数和少量 C++类构成,

    2024年02月16日
    浏览(34)
  • python爬各平台评论并数据分析——数据采集、评论情绪分析、新闻热度

    1.python之matplotlib使用系统字体 用于解决python绘图中,中文字体显示问题 2.cookie与视频页面id(b站、微博等)查看 F12打开网页开发者模式,然后F5刷新,进入控制台中的网络,查看Fetch/XHR 3.爬取wb评论时,最好使用网页手机端 网页手机端:https://m.weibo.cn/?sudaref=cn.bing.com 4.从存储

    2024年02月09日
    浏览(56)
  • 装饰工程管理系统|基于Springboot的装饰工程管理系统设计与实现(源码+数据库+文档)

    装饰工程管理系统-项目立项子系统目录 目录 基于Springboot的装饰工程管理系统设计与实现  一、前言 二、系统功能设计 三、系统实现 1、管理员功能实现 (2)合同报价管理 (3)装饰材料总计划管理 (4)客户管理 2、员工功能实现 (1)新增立项项目 (2)预算报价管理 (

    2024年04月11日
    浏览(39)
  • 装饰工程|装饰工程管理系统-项目立项子系统的设计与实现|基于Springboot的装饰工程管理系统设计与实现(源码+数据库+文档)

    装饰工程管理系统-项目立项子系统目录 目录 基于Springboot的装饰工程管理系统设计与实现  一、前言 二、系统功能设计 三、系统实现 1、管理员功能实现 (2)合同报价管理 (3)装饰材料总计划管理 (4)客户管理 2、员工功能实现 (1)新增立项项目 (2)预算报价管理 (

    2024年02月20日
    浏览(41)
  • 鸿蒙Harmony--状态管理器--@Provide装饰器和@Consume装饰器详解

    今天是1月11日号星期四,农历腊月初一,辞旧的岁月里,愿你守得云开、终见月明,迎新的时光中,愿你心御寒冬、顺遂无忧,岁末冬深,希望接下来的日子里足够幸运,攒足勇气、信心和运气,去迎接新的一年,去遇见更好的自己! 目录 一,定义 二,特性 三,装饰器说明

    2024年02月01日
    浏览(52)
  • 鸿蒙Harmony--状态管理器-@Observed装饰器和@ObjectLink装饰器详解

     经历的越多,越喜欢简单的生活,干净的东西,清楚的感觉,有结果的事,和说到做到的人。把圈子变小,把语放缓,把心放宽,用心做好手边的事儿,该有的总会有的! 目录 一,定义 二,装饰器说明 三,变量的传递/访问规则说明  四,使用 1,简单对象的使用 2,嵌套对

    2024年02月01日
    浏览(55)
  • python中的装饰器(基础装饰器)

    1. 高阶函数 在python中, 如果一个函数的参数是另外一个或几个函数,那么这个函数就是高阶函数 ,如下 上面的函数fun2就是一个高阶函数,因为它的参数是一个函数fun1。 2. 闭包 在python中, 闭包是一个函数,它延伸了变量的作用域,使得在定义变量的作用域失效后,该变量

    2023年04月24日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包