作用
装饰器可以用于用于装饰一个函数或方法,使得在不修改原函数、方法代码的前提下,为方法添加前置或后置操作;
例如突然想要计算一下各个函数的执行时间,又不希望在每一个函数中添加tim.time()来计算执行时间
用法
装饰器的写法网上很多,但是我觉得还是尽量先理解,再知道怎么写会比较好,所以会先说如何理解,在后面重写用法
实现
了解装饰器是如何实现的,远比会写装饰器更重要,简单的说装饰器就是接收一个函数对象,然后先执行前置操作,再执行函数,再执行后置操作;
这么说可能有些抽象,或者举一个不那么恰当的比较贴近生活的例子;
假设你有一台像这样的小风扇:
这台风扇可以充电,有一个开关,打开之后扇叶会旋转,开始工作,当然你也可以插着电打开开关,也可以充好电之后带走,在其他地方打开开关
如果把这个风扇置于一切皆是对象的Python中,风扇就是一个对象,他实现的功能就是出风:
def fengshan(): return '出风'
为了更好和例子结合,我们用pinyin命名
现在我们实现了一个fengshan函数,返回吹风
如果你稍微有点基础,你就能知道如何调用这个方法
def fengshan(): return '出风' print(fengshan())
不要觉得这很基础很墨迹,如果需要理解装饰器,你必须知道,调用函数的方式是函数名称加上括号fengshan()
而这个基础中的基础中的括号()就是执行函数的开关,如果我们不加括号
def fengshan(): return '出风' print(fengshan)
返回的将是一个函数对象(例子中的风扇本身)
<function fengshan at 0x7f8e7c4a6950>
这里的意思是 一个叫fengshan的funciont,地址在0x7f8e7c4a6950
那现在我们就可以把风扇带走,在其他地方使用
def fengshan(): return '出风' func = fengshan print(fengshan) print(func)
返回
<function fengshan at 0x7f570eaf3950>
<function fengshan at 0x7f570eaf3950>
这说明func和fengshan是等价的,他们在同一块内存中,所以当我们执行func() 也等价于执行fengshan
def fengshan(): return '出风' func = fengshan print('下面是执行fengshan') print(fengshan()) print('下面是执行func') print(func())
返回
下面是执行fengshan
出风
下面是执行func
出风
理解到这里之后你也就能理解装饰器的实现了,让我们再看一个例子
def fengshan(): return '出风' def wrapper(func): return func print(fengshan) print(wrapper(fengshan))
这个例子中我们除了保留刚刚一直在用的fengshan函数之外,又定义了一个wrapper
因为python中一切皆是对象,函数也是对象,而函数的入参也可以接收对象,所以函数对象可以作为参数传递给另一个函数wrapper
这个wrapper中什么都没有做,只是返回了接收的func对象,我们打印出来两个对象,可以发现他们其实是同一个对象
<function fengshan at 0x7f9b0c92f950>
<function fengshan at 0x7f9b0c92f950>
现在你就已经理解了装饰器的实现了,而且如果你跟着文中的代码敲一遍,你就已经写了一个装饰器,你只需要稍加修改,比方说,我们在wrapper内部执行接收的func,并且,在前后加上一些操作
def wrapper(func): print('在wrapper中执行func前') print(func()) print('在wrapper中执行func后') wrapper(fengshan)
返回
在wrapper中执行func前
出风
在wrapper中执行func后
如果你觉得很神奇,无法理解,可以回到风扇的图片重新再读一遍,当你理解了上述的代码之后,我们就可以加快速度,完成真正的装饰器的编写
用法
当你成功明白了函数被定义和调用的过程之后,我们开始考虑实际场景,上一段代码中我们还是改变了原有函数的调用
从调用fengshan变成了调用func(fengshan)
我们想要实现不改变原有代码和调用方式的情况下为原有函数添加前置或后置操作,就需要再优化一下我们的装饰器
def fengshan(): print('出风') def wrapper(func): def f(): print('在wrapper中执行func前') func() print('在wrapper中执行func后') return f fengshan = wrapper(fengshan) fengshan()
为了看到执行过程,我们把fengshan内部的return改为print
返回
在wrapper中执行func前
出风
在wrapper中执行func后
这里我们的改变是在wrapper原有的实现中又包了一层方法f,再回想一下我们前面风扇的例子,现在当我们执行wrapper的时候,执行了什么?
wrapper(func)的返回,是一个函数对象f,这个函数对象的开关没有被打开,f中的代码不会被执行
我们又用同名的fengshan对象去接收了这个函数对象f,在最后一行打开fengshan的开关 -- fengshan(),这时候函数对象f中的代码,才刚被执行
如果看不懂的话,建议从风扇图片开始再看一遍,如果你看懂了,建议你也再看一遍,至此,我们就已经完成了一个装饰器,为了更方便使用装饰器,Python给我们提供了更简便的方法
def wrapper(func): def f(): print('在wrapper中执行func前') func() print('在wrapper中执行func后') return f @wrapper def fengshan(): print('出风') fengshan()
返回
在wrapper中执行func前
出风
在wrapper中执行func后
补充知识
如果你已经理解了装饰器的执行逻辑,你也就会知道如何让装饰器支持带参数的方法,这也是我们写装饰器的常规操作
def wrapper(func): def f(*args, **kwargs): print('在wrapper中执行func前') func(*args, **kwargs) print('在wrapper中执行func后') return f @wrapper def fengshan(str_obj): print(str_obj) fengshan(str_obj='出风')
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
Python装饰器,原理
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新动态
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]