百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

Python 装饰器,给你的函数加点“料”!

ztj100 2025-01-09 17:29 13 浏览 0 评论

各位程序猿、攻城狮们,大家好哇!今天咱们来聊聊 Python 里一个神奇的东东——装饰器 (Decorator)。 听到这个名字,是不是感觉有点高大上?别怕别怕,其实它就像我们给函数加个“魔法棒”,咻的一下,就能给函数“升级”一下,增加一些额外的功能,但又不用动它原本的代码,是不是很酷炫?

一、 开场白:你的函数需要“加点料”吗?

咱先来唠唠嗑。 你有没有遇到过这样的情况:

  • 写了好几个函数,都需要在执行前后记录一下日志,难道要每个函数里都写一遍 print('开始执行...') 和 print('执行结束...') 吗?这也太 low 了吧!
  • 有些敏感操作的函数,你想做个权限校验,只有特定用户才能调用,难道要挨个函数里面写 if user.is_admin: 吗?这也太麻烦了吧!
  • 你想统计一下某个函数的运行时间,看看是不是“老牛拉破车”,难道又要改动函数内部的代码,加个计时器?这…谁愿意干啊!

每当遇到这些 “重复劳动” 的时候,我的内心 OS 都是:有没有什么“一劳永逸”的办法,能给这些函数“批量加buff”呢?

嘿嘿,告诉你,还真有!Python 的装饰器就是干这个的!它就像一个“函数调料包”,你想给哪个函数“加点料”,就往它身上“撒”一点,简单粗暴又有效!

二、 装饰器是啥玩意?别光说不练啊!

说了这么多,装饰器到底是个啥呢?别急,咱们先看个简单的例子:

def my_decorator(func):
    def wrapper():
        print("函数执行前,我在加点料!")
        func()
        print("函数执行后,我也没闲着!")
    return wrapper

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

say_hello()

运行一下,看看会输出啥?

函数执行前,我在加点料!
Hello!
函数执行后,我也没闲着!

是不是有点意思了? say_hello 函数原本只是打印 "Hello!",但是经过 @my_decorator 这么一“装饰”,就多了两行额外的输出。

敲黑板,划重点啦!

  • 装饰器本质上是一个 Python 函数 (如上面的 my_decorator)。
  • 它可以接收一个函数作为参数 (如上面的 say_hello)。
  • 它会返回一个新的函数 (如上面的 wrapper)。
  • @my_decorator 这种写法,其实就是个“语法糖”,相当于 say_hello = my_decorator(say_hello)。 是不是感觉一下子就 get 到了?

你可以把装饰器想象成一个“包装纸”,你把原来的函数(比如一个礼物)放进去,经过装饰器这么一“包装”,就变成了一个“加了额外功能”的新礼物。

三、 装饰器的工作原理:幕后的小秘密

咱们再来扒一扒装饰器背后的“小秘密”。 当你用 @my_decorator 装饰 say_hello 的时候,Python 实际上做了这么几件事:

  1. 它把 say_hello 这个函数当作参数,传给了 my_decorator 函数。
  2. my_decorator 函数内部定义了一个新的函数 wrapper,在这个 wrapper 函数里,你可以做一些“加料”的操作(比如打印日志),然后调用原来的 func 函数。
  3. my_decorator 函数最后返回了这个新的 wrapper 函数。
  4. 最终,say_hello 这个名字不再指向原来的函数了,而是指向了 my_decorator 返回的那个 wrapper 函数。

所以,当你调用 say_hello() 的时候,实际上是在执行 wrapper() 函数里面的代码。 是不是感觉瞬间高大上了起来?

四、 装饰器的各种姿势:不止一种玩法!

上面的例子是最简单的装饰器,但装饰器可不止这一种玩法哦!

1. 带参数的装饰器:更灵活的“调料包”

有时候,我们希望装饰器也能接收一些参数,让它可以更灵活地“加料”。 比如,我们想让日志信息可以自定义:

def log(text):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(f"[{text}] {func.__name__} 函数开始执行啦!")
            result = func(*args, **kwargs)
            print(f"[{text}] {func.__name__} 函数执行完毕!")
            return result
        return wrapper
    return decorator

@log('DEBUG')
def my_function(name):
    print(f"Hello, {name}!")

my_function("Alice")

输出结果:

[DEBUG] my_function 函数开始执行啦!
Hello, Alice!
[DEBUG] my_function 函数执行完毕!

注意看! @log('DEBUG') 这种写法,其实相当于 my_function = log('DEBUG')(my_function)。 log('DEBUG') 会先执行,返回一个装饰器函数,然后再用这个返回的装饰器函数去装饰 my_function。 是不是有点绕?多看几遍就明白了!

2. 装饰器装饰带参数的函数:雨露均沾

上面的例子里,被装饰的函数 say_hello 和 my_function 分别是没有参数和有一个参数的情况。 如果被装饰的函数有多个参数,我们该怎么办呢?

在 wrapper 函数里使用 *args 和 **kwargs 就能完美解决! *args 用来接收所有位置参数,**kwargs 用来接收所有关键字参数,保证“雨露均沾”,不会漏掉任何一个参数。

3. 类装饰器:让装饰器也“面向对象”

除了用函数来做装饰器,我们还可以用类来实现装饰器。 只需要在类里面实现 __call__ 方法,这个类的实例就可以像函数一样被调用,也就可以作为装饰器来使用了。

class Counter:
    def __init__(self, func):
        self.func = func
        self.count = 0

    def __call__(self, *args, **kwargs):
        self.count += 1
        print(f"函数 {self.func.__name__} 第 {self.count} 次被调用!")
        return self.func(*args, **kwargs)

@Counter
def my_action():
    print("执行了一个动作!")

my_action()
my_action()

输出结果:

函数 my_action 第 1 次被调用!
执行了一个动作!
函数 my_action 第 2 次被调用!
执行了一个动作!

类装饰器通常用于维护一些状态信息,比如上面的计数器。

五、 装饰器的应用场景:哪里需要哪里搬!

装饰器在实际开发中可是非常实用的 “小能手”! 来看看它都能帮我们做些什么:

  • 日志记录: 统一记录函数的调用信息、参数、返回值等。
  • 性能监控: 统计函数的运行时间,找出性能瓶颈。
  • 权限校验: 检查用户是否有权限调用某个函数。
  • 缓存: 缓存函数的计算结果,避免重复计算。
  • 事务处理: 在函数执行前后开启和提交/回滚事务。
  • 路由控制 (Web 框架): 将 URL 映射到对应的处理函数。

可以说,只要你想在不修改原函数代码的情况下,给函数增加一些额外的功能,装饰器都能派上用场!

六、 总结一下:给你的技能树点亮新技能!

好啦,今天关于 Python 装饰器的讲解就到这里啦! 希望通过这篇轻松幽默的文章,让你对装饰器有了更深入的理解。 记住,装饰器其实并没有那么可怕,它只是 Python 提供的一个强大的 “语法糖”,能让你的代码更加简洁、优雅、易于维护。

最后,留个小思考题: 如果一个函数被多个装饰器装饰,它们的执行顺序是怎样的呢? 欢迎在评论区留言讨论!

下一篇,咱们可以聊聊 Python 的生成器和迭代器,也是 Python 中非常重要的概念哦! 敬请期待! 溜啦溜啦~

相关推荐

干货 | 各大船公司VGM提交流程(msc船运公司提单查询)

VGM(VerifiedGrossMass)要来了,大外总管一本正经来给大家分享下各大船公司提交VGM流程。1,赫伯罗特(简称HPL)首先要注册账户第一,登录进入—选择product------...

如何修改图片详细信息?分享三个简单方法

如何修改图片详细信息?分享三个简单方法我们知道图片的详细信息里面包含了很多属性,有图片的创建时间,修改时间,地理位置,拍摄时间,还有图片的描述等信息。有时候为了一些特殊场景的需要我们需要对这些信息进行...

实用方法分享:没有图像处理软件,怎么将一张照片做成九宫格?

在发朋友圈时,如果把自己的照片做成九宫格,是不是更显得高大上?可能你问,是不是要借助图片处理软件,在这里,我肯定告诉你,不需要!!!你可能要问,那怎么实现呢?下面你看我是怎么做的,一句代码都不写,只是...

扫描档PDF也能变身“最强大脑”?RAG技术解锁尘封的知识宝藏!

尊敬的诸位!我是一名物联网工程师。关注我,持续分享最新物联网与AI资讯和开发实战。期望与您携手探寻物联网与AI的无尽可能。今天有网友问我扫描档的PDF文件能否做知识库,其实和普通pdf处理起来差异...

这两个Python库,轻而易举就能实现MP4与GIF格式互转,太好用了

mp4转gif的原理其实很简单,就是将mp4文件的帧读出来,然后合并成一张gif图。用cv2和PIL这两个库就可以轻松搞定。importglobimportcv2fromPILimpo...

python图片处理之图片切割(python把图片切割成固定大小的子图)

python图片切割在很多项目中都会用到,比如验证码的识别、目标检测、定点切割等,本文给大家带来python的两种切割方式:fromPILimportImage"""...

python+selenium+pytesseract识别图片验证码

一、selenium截取验证码#私信小编01即可获取大量Python学习资源#私信小编01即可获取大量Python学习资源#私信小编01即可获取大量Python学习资源importjso...

如何使用python裁剪图片?(python图片截取)

如何使用python裁剪图片如上图所示,这是一张包含了各类象棋棋子的图片。我们需要将其中每一个棋子都裁剪出来,此时可以利用python的...

Python rembg 库去除图片背景(python 删除图片)

rembg是一个强大的Python库,用于自动去除图片背景。它基于深度学习模型(如U^2-Net),能够高效地将前景物体从背景中分离,生成透明背景的PNG图像。本教程将带你从安装到实际应用...

「python脚本」批量修改图片尺寸&视频安帧提取

【python脚本】批量修改图片尺寸#-*-coding:utf-8-*-"""CreatedonThuAug2316:06:352018@autho...

有趣的EXCEL&vba作图(vba画图表)

还记不记得之前有个日本老爷爷用EXCEL绘图,美轮美奂,可谓是心思巧妙。我是没有那样的艺术细胞,不过咱有自己的方式,用代码作图通过vba代码将指定的图片写入excel工作表中,可不是插入图片哦解题思...

怎么做到的?用python制作九宫格图片,太棒了

1.应用场景当初的想法是:想把一张图切割成九等份,发布到微信朋友圈,切割出来的图片,上传到朋友圈,发现微信不按照我排列的序号来排版。这样的结果是很耗时间的。让我深思,能不能有一种,直接拼接成一张...

Python-连续图片合成视频(python多张图叠加为一张)

前言很多时候,我们需要将图片直接转成视频。下面介绍用python中的OpenCV将进行多张图合成视频。cv2安装不要直接用pipinstallcv2,这会报错。有很多人建议用打开window自带的...

如何把多个文件夹里的图片提取出来?文件夹整理合并工具

在项目管理中,团队成员可能会将项目相关的图片资料分散存储在不同的文件夹中,以便于分类和阶段性管理。然而,当项目进入汇报或总结阶段时,需要将所有相关图片整合到一个位置,以便于制作演示文稿、报告或进行项目...

超简单!为图片和 PDF 上去掉水印(pdf图片和水印是一体,怎么去除)

作者:某某白米饭...

取消回复欢迎 发表评论: