当前位置: 首页 > news >正文

[python] 之 装饰器

 

  装饰器本质上是一个python函数,它可以让其它函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象。装饰器主要用于插入日志、性能测试、事务处理、缓存及权限校验等,解决代码重复使用。值得注意的是,内层函数保留(记忆)了外层函数的(参数)状态。

一、装饰器创建

  装饰器的语法以@开头,接着是装饰器函数的变量名和可选参数,紧接着是被修饰函数的定义及被修饰函数的可选参数。

  语法:

  @decorator(dec_opt_args)

  def fuc2Bdecorated(func_opt_args):

    func_body

 1 def dec1(func1):
 2     def wrapper1():
 3         print('hello!')
 4         return func1
 5     return wrapper1
 6 @dec1
 7 def test():
 8     pass
 9 
10 test()
11 #输出
12 hello!

  装饰器可以像函数一样堆叠起来,如下:

 1 def dec1(func1):
 2     def wrapper1():
 3         print('hello!')
 4         return func1
 5     return wrapper1
 6 
 7 def dec2(func2):
 8     def wrapper2():
 9         print ('Pyhton!')
10         return func2
11     return wrapper2
12  
13 @dec2
14 @dec1
15 def test():
16     pass
17 if __name__ == '__main__':
18   test()
19 #输出
20 Python!

  此时,函数变量名test作为一个参数传递给了装饰器函数dec1,并返回wrapper1;然后wrapper1作为参数传递给了dec2,并返回了wrapper2;最后test()等价于wrapper2()的调用,即dec2(dec1(test()))。注意,如果装饰器函数有参数,应现执行装饰器函数,并返回一个可调用函数,继续遵循上述的运算规则;如果被修饰的函数有参数,则作为最后返回的可调用的函数的参数,进行最后的运算,并返回值,执行结束。(如下)。

二、有参数的函数装饰器

  2.1 被修饰的函数含有参数

  该函数等价于dec2(dec1(test('dec00')))

 1 def dec1(func1): #func = test
 2     def wrapper1(arg1): # arg1 = arg2
 3         print(arg1+' + hello!')
 4         return func1(arg1) #func1 = test
 5     return wrapper1
 6 
 7 def dec2(func2): #func2 = wrapper1
 8     def wrapper2(arg2): # arg2 = 'dec00'
 9         print (arg2+' + Pyhton!')
10         return func2(arg2) #wrapper1(arg2)
11     return wrapper2
12 
13 @dec2
14 @dec1
15 def test(t):
16     print(t+' + test')
17 if __name__ == '__main__':
18   test('dec00')
19 
20 #输出
21 dec00 + Pyhton!
22 dec00 + hello!
23 dec00 + test

  2.2 装饰器函数含有参数

  该函数首先执行dec2('dec2'),返回dec21,然后整个函数等价于dec21(dec1(test01('dec01')))或者dec2('dec2')(dec1(test01('dec01'))),请读者认真体会以上两种情况。

 1 def dec1(func1): #func = test01
 2     def wrapper1(arg1): 
 3         print(arg1+' + hello!')
 4         return func1(arg1)
 5     return wrapper1
 6  
 7 def dec2(level): #level = 'dec2'
 8     def dec21(func2): #func2 = wrapper1
 9         def wrapper2(arg2): #arg2 = 'dec01'
10             print (level+' + '+arg2+' + Pyhton!')
11             return func2(arg2) #func2 = wrapper1
12         return wrapper2
13     return dec21
14 @dec2('dec2')
15 @dec1
16 def test01(t):
17     print(t +' + test01')
18 if __name__ == "__main__":
19     test01('dec01')
20 #输出
21 dec2 + dec01 + Pyhton!
22 dec01 + hello!
23 dec01 + test01

三、基于类的装饰器

  根据装饰器语法及其运算性质,可知装饰器函数本身必须是可调用(callable)的,然后返回一个可调用(callable)对象。在Python中一般callable对象都是函数,但也有例外。只要某个对象重载了__call__()方法,那么这个对象就是callable的。

   下面是可调用的类:

 1 class P(object):
 2     def __call__(self):
 3         print ('callable')
 4     def func(self):
 5         print ('class')
 6     
 7 i = P()
 8 i.func()
 9 i()
10 
11 #输出
12 class
13 callable

  3.1 基于可调用的类,创建装饰器:

 1 class P(object):
 2     def __init__(self,func):
 3         self.func = func
 4     def __call__(self):
 5         print ('callable')
 6         return self.func()
 7 @P
 8 def test():
 9     print('test')
10 if __name__ == "__main__" : 
11     test()
12 #输出
13 callable
14 test

  在上述函数调用过程中,类P是一个可调用的对象,类似于函数。上述装饰器执行等价于P(test())。

  3.2 带参数的类装饰器

 1 class P(object):
 2     def __init__(self,level):
 3         self.level = level # level = 'level'
 4     def __call__(self,func): # func = test
 5         def wrapper(t): #t = 't'
 6             print (self.level + ' + callable')
 7             return func(t) # test('t')
 8         return wrapper
 9 @P('level')
10 def test(t):
11     print('test')
12 if __name__ == "__main__" : 
13     test('t')
14 
15 #输出
16 level + callable
17 test

  此装饰器执行时,首先调用类P,初始化类并返回了函数变量名wrapper,此时该函数的参数,来源与被修饰的函数的参数,这一点和基于函数的装饰器是等同的。

转载于:https://www.cnblogs.com/xiaofeiIDO/p/6024639.html

相关文章:

  • linux--dhcp服务器
  • 浪潮NF5280M3安装Windows Server 2008 R2注意事项
  • 关于使用/来 dispatcherServlet 的url-pattern带来的问题
  • c语言中函数的形参test(int *a)?
  • Core Bluetooth下实现两个设备进行互联
  • MyEclipse开发WebService教程
  • noi 2989 糖果
  • 微软Hyper-v管理——迁移虚拟(奇葩问题)
  • [Android Pro] listView和GridView的item设置的高度和宽度不起作用
  • 每天学点数据结构与算法
  • Zabbix服务器监控系统部署之自定义监控项的添加及配置(二)
  • PYTHON 黑帽编程 1.5 使用 WIRESHARK 练习网络协议分析
  • Javascript 函数节流
  • 利用python做数据分析(六)-reindex
  • GitHub 小试
  • JS学习笔记——闭包
  • Vue小说阅读器(仿追书神器)
  • 浮动相关
  • - 概述 - 《设计模式(极简c++版)》
  • 官方解决所有 npm 全局安装权限问题
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 如何优雅的使用vue+Dcloud(Hbuild)开发混合app
  • 世界上最简单的无等待算法(getAndIncrement)
  • 微信开放平台全网发布【失败】的几点排查方法
  • 系统认识JavaScript正则表达式
  • 一道面试题引发的“血案”
  • 优秀架构师必须掌握的架构思维
  • Java性能优化之JVM GC(垃圾回收机制)
  • 交换综合实验一
  • ​ssh-keyscan命令--Linux命令应用大词典729个命令解读
  • ​创新驱动,边缘计算领袖:亚马逊云科技海外服务器服务再进化
  • $$$$GB2312-80区位编码表$$$$
  • (arch)linux 转换文件编码格式
  • (附源码)springboot车辆管理系统 毕业设计 031034
  • (附源码)springboot猪场管理系统 毕业设计 160901
  • (附源码)ssm基于jsp高校选课系统 毕业设计 291627
  • (附源码)ssm经济信息门户网站 毕业设计 141634
  • (四)【Jmeter】 JMeter的界面布局与组件概述
  • (转)ObjectiveC 深浅拷贝学习
  • .NET 8.0 中有哪些新的变化?
  • .NET 动态调用WebService + WSE + UsernameToken
  • .net 重复调用webservice_Java RMI 远程调用详解,优劣势说明
  • .NET/C# 反射的的性能数据,以及高性能开发建议(反射获取 Attribute 和反射调用方法)
  • .Net+SQL Server企业应用性能优化笔记4——精确查找瓶颈
  • .NET单元测试
  • .Net环境下的缓存技术介绍
  • .NET设计模式(7):创建型模式专题总结(Creational Pattern)
  • .Net中的集合
  • /bin/bash^M: bad interpreter: No such file or directory
  • /bin/bash^M: bad interpreter: No such file ordirectory
  • @ComponentScan比较
  • @WebService和@WebMethod注解的用法
  • [ vulhub漏洞复现篇 ] Hadoop-yarn-RPC 未授权访问漏洞复现
  • [20160902]rm -rf的惨案.txt
  • [AIGC codze] Kafka 的 rebalance 机制