文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

搞定三大神器之 Python 装饰器

2024-12-10 16:01

关注

[[344466]]

1. 什么是装饰器

对于受到封装的原函数比如f来说,装饰器能够在f函数执行前或者执行后分别运行一些代码。

2. 装饰器的结构

装饰器也是一个函数,它装饰原函数f或类cls后,再返回一个函数g

装饰一个函数:

  1. def decorator(f): 
  2.   # 定义要返回的函数 
  3.   def g(): 
  4.     print('函数f执行前的动作') 
  5.     f() 
  6.     print('函数f执行后的动作') 
  7.   return g 

装饰一个类:

  1. def decorator(cls): 
  2.   # 定义要返回的函数 
  3.   def g(): 
  4.     print('类cls执行前的动作') 
  5.     f() 
  6.     print('类cls执行后的动作') 
  7.   return g 

使用装饰器很简单,@+自定义装饰器 装饰要想装饰的函数。

3. 为什么要这样

要想理解装饰器为什么要有这种结构,要首先想明白装饰器的目标是什么。

它的价值在于为原函数f增加一些行为,前提必须不能破坏函数f,所以肯定不能改变f的内部结构,所以只能在调用f前后定义一些行为。

同时,装饰器函数decorator返回值又是什么?你可以思考下,返回一个函数是再好不过的了,它包装了原函数f.

4. 装饰一个函数

printStar函数接收一个函数f,返回值也是一个函数,所以满足装饰器的结构要求,所以printStar是一个装饰器。

  1. def printStar(f): 
  2.     def g(): 
  3.         print('*'*20) 
  4.         f() 
  5.         print('*'*20) 
  6.     return g 

printStar装饰器实现f函数执行前、后各打印20个*字符。

使用printStar:

  1. @printStar 
  2. def f(): 
  3.     print('hello world') 

调用:

  1. if __name__ == '__main__': 
  2.    ### 改变函数功能 
  3.    f() 

打印结果:

  1. ******************** 
  2. hello world 
  3. ******************** 

可以很方便的装饰要想装饰的其他函数,如下:

  1. @printStar 
  2. def g(): 
  3.     print('welcome to Python') 

5. 装饰一个类

除了可以装饰函数f外,还可以装饰类cls,两者原理都是一样的。

下面给出一个装饰器实现单例模式的例子,所谓单例就是类只有唯一实例,不能有第二个。

  1. def singleton(cls): 
  2.    instance = {} 
  3.  
  4.    def get_instance(*args, **kwargs): 
  5.        if cls not in instance: 
  6.            instance[cls] = cls(*args, **kwargs) 
  7.        return instance[cls] 
  8.    return get_instance 

定义字典instance,键值对分别为类和实例,这样确保只cls()一次。

使用装饰器singleton修饰类:

  1. @singleton 
  2. class CorePoint: 
  3.    pass 

测试:

  1. if __name__ == '__main__': 
  2.    ### 改变类的功能 
  3.    c1 = CorePoint() 
  4.    c2 = CorePoint() 
  5.    print(c1 is c2) # True 

6. 装饰器层叠

上面原函数f不仅能被一个装饰器修饰,还能被n多个装饰器修饰。

下面再定义一个装饰器printLine,被修饰函数执行前后打印20个:

  1. def printLine(f): 
  2.     def g(): 
  3.         print('-'*20) 
  4.         f() 
  5.         print('-'*20) 
  6.     return g 

使用上文定义好的printStar和printLine同时装饰函数f:

  1. @printStar 
  2. @printLine 
  3. def f(): 
  4.     print('hello world') 

此时再调用函数f:

  1. if __name__ == '__main__': 
  2.    ### 改变函数功能 
  3.    f() 

打印结果:

  1. ******************** 
  2. -------------------- 
  3. hello world 
  4. -------------------- 
  5. ******************** 

f被装饰后,先打印*,再打印 -

层叠多一层,原函数f就变强大一层。使用装饰器,还能实现功能抽离,进一步实现松耦合。

7. 温馨提醒

打印原函数f的名字__name__,结果为f

  1. In [1]: def f():  
  2.    ...:     pass  
  3.  
  4. In [4]: f.__name__                                                               
  5. Out[4]: 'f' 

但是,被装饰后函数名字f变为g,这不是我们希望的!

  1. @printStar 
  2. def f(): 
  3.   pass 
  4.  
  5. f() 
  6. f.__name__ # g 

Python提供的解决方案:使用functools模块中的wraps装饰器:

  1. from functools import wraps 
  2.  
  3. def printStar(f): 
  4.     @wraps(f) 
  5.     def g(): 
  6.         print('*'*20) 
  7.         f() 
  8.         print('*'*20) 
  9.     return g 

此时再打印被装饰后f的名字,显示f,正常!

 

来源:Python与算法社区内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯