二十年前,闭包爱上了语法糖,从此Python多了一个叫做装饰器的小伙伴

1. 引子

二十年前,大约也是这个时节,闭包(Closure),一个帅气的小伙子,无可救药地爱上了长相甜美的语法糖(Syntactic Sugar)姑娘。结果呢,后面的故事你们就都知道了,2004年11月30号,Python2.4为他们举行了隆重的婚礼,闭包和语法糖的爱情结晶——小帅哥装饰器作为花童,也参加了他们的婚礼。

2. 闭包

作为一种编程语言特性,闭包得到了很多编程语言的支持,Python也不例外。所谓闭包,在Python中指的是携带一个或多个自由量的函数。闭包函数的自由量不是函数的参数,而是生成这个函数时的环境变量。一旦闭包生成了,自由变量会绑定在函数上,即使离开创造它的环境,自由量依旧有效。总结一下,闭包的概念有以下三个要点。

  • 闭包是一个函数
  • 闭包函数是由其他代码生成的
  • 闭包函数携带了生成环境的信息

我有一篇专门讲闭包的博文,名为《理解Python闭包,这应该是最好的例子》,这里就不再赘述了,只给出一个闭包的例子。

>>> import time
>>> def kids_factor(name): # 定义一个宝宝工厂
		t0 = time.time()
		def kid():
			t1 = time.time()
			print('我是%s,已经出生%d秒钟了'%(name, int(t1-t0)))
		return kid

>>> kid_jack = kids_factor('杰克') # 生产一个名为杰克的宝宝
>>> kid_john = kids_factor('约翰') # 生产一个名为约翰的宝宝
>>> kid_jack() # 让杰克出来走两步,看到杰克已经出生49秒钟了
我是杰克,已经出生49秒钟了
>>> kid_john() # 让约翰出来走两步,看到约翰已经出生15秒钟了
我是约翰,已经出生15秒钟了
>>> kid_john() # 再让约翰出来走两步,看到约翰已经出生22秒钟了
我是约翰,已经出生22秒钟了
>>> kid_jack() # 再让杰克出来走两步,看到杰克已经出生68秒钟了
我是杰克,已经出生68秒钟了

通过这个例子可以看到,宝宝(闭包函数)的出生时间t0已经被包含在闭包函数中,让宝宝走两步(运行闭包函数),t1一行中time.time()才被执行。

3. 语法糖

语法糖,听起来有点甜腻,看上去似乎是用“语法”来限定修饰“糖”,其实呢,“糖”只是修饰词,“语法”才是词干。语法糖本质上也是编程语言的一种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。因此,我觉得叫做糖衣语法更合适。

语法糖并不单一指一种语法,是若干糖衣语法的合集。比如,我们经常用到的所谓“三元表达”,就是一种典型的语法糖。

>>> y = 5
>>> x = -1 if y < 0 else 1
>>> x
1

本文引子闭包爱上的语法糖,则是@这个函数装饰符。函数装饰符和装饰函数必须独占一行,后面紧接被装饰的函数定义。 @函数装饰符将被装饰的函数作为参数传递给装饰函数,最后返回装饰后的同名函数。

4. 装饰器

4.1 装饰函数无参数

通常,装饰函数只接受一个参数,也就是被装饰的函数。这种情况下,无论被装饰的函数有无参数,都可以使用下面例子中的标准写法。

>>> import time
>>> def timer(func):
		def wrapper(*args, **kwds):
			t0 = time.time()
			func(*args, **kwds)
			t1 = time.time()
			print('耗时%0.3f秒'%(t1-t0,))
		return wrapper

>>> @timer
def do_something(delay):
	print('函数do_something开始')
	time.sleep(delay)
	print('函数do_something结束')
	
>>> do_something(3)
函数do_something开始
函数do_something结束
耗时3.086

4.2 装饰函数有参数

如果装饰器函数本身也需要传递参数,则需要在外层再包裹一层。下面的代码中,装饰器函数timer通过param和**kvs接受可变参数和关键字参数,也就是任意形式的参数;而args和**kwds则是被装饰的函数的参数。

>>> def timer(*param, **kvs):
	def wrapper(func):
		def _wrapper(*args, **kwds):
			print('这是装饰器函数的参数:', param, kvs)
			t0 = time.time()
			func(*args, **kwds)
			t1 = time.time()
			print('耗时%0.3f秒'%(t1-t0,))
		return _wrapper
	return wrapper

>>> @timer('ok', name='xufive', age=18)
def do_something(delay):
	print('函数do_something开始')
	time.sleep(delay)
	print('函数do_something结束')

	
>>> do_something(3)
这是装饰器函数的参数: ('ok',) {'name': 'xufive', 'age': 18}
函数do_something开始
函数do_something结束
耗时3.068

有一点需要注意:4.2中,即使装饰函数无参数(此时最好使用4.1的形式),使用装饰器时也必须写作@timer(),而不是@timer。这并不难理解,因为@timer和@timer()不同,前者并没有立即运行timer函数,后者则是立即运行了timer函数,后面的就和4.1形式类似了。

相关推荐
<p> <strong><span style="font-size:20px;color:#FF0000;">本课程主要针对计算机相关专业正在做毕设学生与需要项目实战练习Java学习者</span></strong> </p> <p> <span style="color:#FF0000;"><strong><span style="font-size:18px;">1. 包含:<span style="color:#FFFF00;background-color:#FF0000;">项目源码、</span><span style="color:#FFFF00;background-color:#FF0000;">项目文档、数据库脚本、软件工具</span>等所有资料</span></strong></span> </p> <p> <span style="color:#FF0000;"><strong><span style="font-size:18px;">2. 手把手带你从零开始部署运行本套系统</span></strong></span> </p> <p> <span style="color:#FF0000;"><strong><span style="font-size:18px;">3. 该项目附带源码资料可作为毕设使用</span></strong></span> </p> <p> <span style="color:#FF0000;"><strong><span style="font-size:18px;">4. 提供技术答疑和远程协助指导</span></strong></span><strong><span style="font-size:18px;"></span></strong> </p> <p> <br /> </p> <p> <span style="font-size:18px;"><strong>项目运行截图:</strong></span> </p> <p> <strong><span style="font-size:18px;">1)系统登陆界面</span></strong> </p> <p> <strong><span style="font-size:18px;"><img src="https://img-bss.csdn.net/202002241015433522.png" alt="" /><br /> </span></strong> </p> <p> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;">2)学生模块</span></strong></span></strong> </p> <p> <strong><span style="font-size:18px;"><img src="https://img-bss.csdn.net/202002241015575966.png" alt="" /></span></strong> </p> <p> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;">3)教师模块</span></strong></span></strong> </p> <p> <strong><span style="font-size:18px;"><img src="https://img-bss.csdn.net/202002241016127898.png" alt="" /></span></strong> </p> <p> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;">4)系统管理员</span></strong></span></strong> </p> <p> <strong><span style="font-size:18px;"><img src="https://img-bss.csdn.net/202002241016281177.png" alt="" /></span></strong> </p> <p> <strong><span style="font-size:18px;"><img src="https://img-bss.csdn.net/202002241016369884.png" alt="" /></span></strong> </p> <p> <strong><span style="font-size:18px;"><br /> </span></strong> </p> <p> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;">更Java毕设项目请关注我毕设系列课程 <a href="https://edu.csdn.net/lecturer/2104">https://edu.csdn.net/lecturer/2104</a></span></strong></span></strong> </p> <p> <strong><span style="font-size:18px;"><br /> </span></strong> </p>
<p> 课程演示环境:Windows10  </p> <p> 需要学习<span>Ubuntus</span>系统<span>YOLOv4-tiny</span>同学请往《<span>YOLOv4-tiny</span>目标检测实战:训练自己数据集》 <span></span> </p> <p> <span> </span> </p> <p> <span style="color:#E53333;">YOLOv4-tiny</span><span style="color:#E53333;">来!速度大幅提升!</span><span></span> </p> <p> <span> </span> </p> <p> <span>YOLOv4-tiny</span>在<span>COCO</span>上性能可达到:<span>40.2% AP50, 371 FPS (GTX 1080 Ti)</span>。相较于<span>YOLOv3-tiny</span><span>AP</span>和<span>FPS</span>性能有巨大提升。并且<span>YOLOv4-tiny</span>权重文件只有<span>23MB</span>适合在移动端、嵌入式设备、边缘计算设备上部署。<span></span> </p> <p> <span> </span> </p> <p> 本课程将手把手地教大家使用<span>labelImg</span>标注和使用<span>YOLOv4-tiny</span>训练自己数据集。课程实战分为两个项目:单目标检测(足球目标检测)和目标检测(足球和梅西同时检测)。<span></span> </p> <p> <span> </span> </p> <p> 本课程<span>YOLOv4-tiny</span>使用<span>AlexAB/darknet</span>在<span>Windows10</span>系统上做项目演示。包括:<span>YOLOv4-tiny</span>网络结构、安装<span>YOLOv4-tiny</span>、标注自己数据集、整理自己数据集、修改配置文件、训练自己数据集、测试训练出网络模型、性能统计<span>(mAP</span>计算<span>)</span>和先验框聚类分析。 <span> </span> </p> <p> <span> </span> </p> <p> 除本课程《<span>Windows</span>版<span>YOLOv4-tiny</span>目标检测实战:训练自己数据集》外本人推出有关<span>YOLOv4</span>目标检测系列课程。请持续关注该系列其它视频课程包括:<span></span> </p> <p> 《<span>Windows</span>版<span>YOLOv4</span>目标检测实战:训练自己数据集》<span></span> </p> <p> 《<span>Windows</span>版<span>YOLOv4</span>目标检测实战:人脸口罩佩戴识别》<span></span> </p> <p> 《<span>Windows</span>版<span>YOLOv4</span>目标检测实战:中国交通标志识别》<span></span> </p> <p> 《<span>Windows</span>版<span>YOLOv4</span>目标检测:原理与源码解析》<span></span> </p> <p> <span> <img alt="" src="https://img-bss.csdnimg.cn/202007061503586145.jpg" /></span> </p> <p> <span><img alt="" src="https://img-bss.csdnimg.cn/202007061504169339.jpg" /><br /> </span> </p>
©️2020 CSDN 皮肤主题: 代码科技 设计师:Amelia_0503 返回首页
实付 15.20元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值