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

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

ztj100 2025-01-09 17:29 17 浏览 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 中非常重要的概念哦! 敬请期待! 溜啦溜啦~

相关推荐

Vue3非兼容变更——函数式组件(vue 兼容)

在Vue2.X中,函数式组件有两个主要应用场景:作为性能优化,因为它们的初始化速度比有状态组件快得多;返回多个根节点。然而在Vue3.X中,有状态组件的性能已经提高到可以忽略不计的程度。此外,有状态组...

利用vue.js进行组件化开发,一学就会(一)

组件原理/组成组件(Component)扩展HTML元素,封装可重用的代码,核心目标是为了可重用性高,减少重复性的开发。组件预先定义好行为的ViewModel类。代码按照template\styl...

Vue3 新趋势:10 个最强 X 操作!(vue.3)

Vue3为前端开发带来了诸多革新,它不仅提升了性能,还提供了...

总结 Vue3 组件管理 12 种高级写法,灵活使用才能提高效率

SFC单文件组件顾名思义,就是一个.vue文件只写一个组件...

前端流行框架Vue3教程:17. _组件数据传递

_组件数据传递我们之前讲解过了组件之间的数据传递,...

前端流行框架Vue3教程:14. 组件传递Props效验

组件传递Props效验Vue组件可以更细致地声明对传入的props的校验要求...

前端流行框架Vue3教程:25. 组件保持存活

25.组件保持存活当使用...

5 个被低估的 Vue3 实战技巧,让你的项目性能提升 300%?

前端圈最近都在卷性能优化和工程化,你还在用老一套的Vue3开发方法?作为摸爬滚打多年的老前端,今天就把私藏的几个Vue3实战技巧分享出来,帮你在开发效率、代码质量和项目性能上实现弯道超车!一、...

绝望!Vue3 组件频繁崩溃?7 个硬核技巧让性能暴涨 400%!

前端的兄弟姐妹们五一假期快乐,谁还没在Vue3项目上栽过跟头?满心欢喜写好的组件,一到实际场景就频频崩溃,页面加载慢得像蜗牛,操作卡顿到让人想砸电脑。用户疯狂吐槽,领导脸色难看,自己改代码改到怀疑...

前端流行框架Vue3教程:15. 组件事件

组件事件在组件的模板表达式中,可以直接使用...

Vue3,看这篇就够了(vue3 从入门到实战)

一、前言最近很多技术网站,讨论的最多的无非就是Vue3了,大多数都是CompositionAPI和基于Proxy的原理分析。但是今天想着跟大家聊聊,Vue3对于一个低代码平台的前端更深层次意味着什么...

前端流行框架Vue3教程:24.动态组件

24.动态组件有些场景会需要在两个组件间来回切换,比如Tab界面...

前端流行框架Vue3教程:12. 组件的注册方式

组件的注册方式一个Vue组件在使用前需要先被“注册”,这样Vue才能在渲染模板时找到其对应的实现。组件注册有两种方式:全局注册和局部注册...

焦虑!Vue3 组件频繁假死?6 个奇招让页面流畅度狂飙 500%!

前端圈的朋友们,谁还没在Vue3项目上踩过性能的坑?满心期待开发出的组件,一到高并发场景就频繁假死,用户反馈页面点不动,产品经理追着问进度,自己调试到心态炸裂!别以为这是个例,不少人在电商大促、数...

前端流行框架Vue3教程:26. 异步组件

根据上节课的代码,我们在切换到B组件的时候,发现并没有网络请求:异步组件:...

取消回复欢迎 发表评论: