前言
装饰器是Python中的一个重要概念,多用于在不修改原函数的基础上,为函数增加额外的功能。

基础装饰器
例如小李给女朋友买了一款iPhone12作为生日礼物,手机原封未拆封。

def gift():print('iPhone12')gift()   # 运行显示礼物信息

但还是觉得礼物太单薄,于是又买了一盒德芙巧克力,一支dior的口红,并找了个精美的礼品盒包装了一下,盒子里放满了泡沫球。

def gift():print('iPhone12')def box(gift):print('='*5 + '礼物盒' + '='*5)print('一盒泡沫球')print('好多巧克力')print('一支dior口红')return giftgift = box(gift)   # 将礼物包装后作为礼物
gift()  # 显示礼物信息

运行后显示如下:

=====礼物盒=====
一盒泡沫球
好多巧克力
一支dior口红
iPhone12

这个box便是一个装饰器,它的参数是一个函数对象,同数字、字符串、列表、字典等数据类型一样,函数和类也可以作为函数的参数使用,毕竟在Python里人人平等,一切皆对象。

box在使用时依然返回了原来的gift,只是在拿到这个gift之前增加了两个额外的惊喜,然后我们把box作为gift使用即可。

装饰器本质上就是以函数作为参数,对函数做一些处理,并替换原函数的一种高阶函数。

上例中,使用装饰器表示为如下。

def box(gift):   #  以函数为参数的装饰器print('='*5 + '礼物盒' + '='*5)print('一盒泡沫球')print('好多巧克力')print('一支dior口红')return gift@box        # 挂载装饰器,会自动替换原函数
def gift():print('iPhone12')gift()   # 这里面得到的gift实际上是装饰后的gift即`box(gift)`

运行后显示和上例相同。

处理函数参数

小李突然想到,买哪个颜色应该征询下女友的意见,也就是原来的gift应支持一个可供选择的颜色参数。

def gift(color):print(f'iPhone12{color}版')

作为一个细心的boyfriend,小李需要根据对应的手机颜色选择同样颜色的泡沫球,也就是需要能获取到,被装饰的gift函数的参数。
这时候我们需要在盒子内部(box装饰器),重新准备一个新的礼物,根据颜色参数做不同的处理,然后根据颜色拿到指定的iPhone12礼物。

def box(gift):print('='*5 + '礼物盒' + '='*5)def new_gift(color):  # 准备一个新的礼物,参数和原gift参数一致print(f'一盒{color}泡沫球')  # 根据颜色准备泡沫球print('好多巧克力')print('一支dior口红')return gift(color)  # 根据颜色拿到指定的iPhone12return new_gift   # 返回新礼物,新礼物调用时,增加一些惊喜,并返回原有礼物gift(color)的结果。@box
def gift(color):print(f'iPhone12{color}版')gift('红色')   # 实际上这里的gift是被box装饰后狸猫换太子的new_gift函数,而new_gift('红色'),返回原gift('红色')的结果。

在box内部为了根据参数做对应处理,我们新建了一个函数,函数内部也可以定义内部函数,内部函数new_gift可以获取并使用外部box函数的参数,如gift。

为了能获取到原有函数gift的参数,我们需要建立一个傀儡函数new_gift,这个函数和原函数gift的参数一致、返回结果一致,即new_gift(‘红色’)返回的就是gift(‘红色’)。

然后狸猫换太子,不再返回原来的gift函数对象,而是返回替换的new_gift函数对象。

运行后显示

=====礼物盒=====
一盒红色泡沫球
好多巧克力
一支dior口红
iPhone12红色版

注意:在装饰器box里,要返回一个函数对象,如上例中的return gift或本例中的return new_gift。而在傀儡函数new_gift中,为了和原函数gift结果一致,要返回原函数的调用结果即gift(color)。

从普遍意义上讲,作为商家,为了装饰器box可以包装任何形式的礼物,无论礼物有什么参数都可以满足,这就要求我们的傀儡函数new_gift支持任意类型的参数即def new_gift(args, **kwargs)。
然后把无论什么参数
args, **kwargs交由原函数gift(*args, **kwargs)处理即可。
修改后,我们便得到一个通用的装饰器,可以包装任何礼物。

def box(gift):print('='*5 + '礼物盒' + '='*5)def new_gift(*args, **kwargs):    # 接受任意数量的参数if args and len(args) > 0:   # 由于参数不确定了,我们假设万一有参数,第一个参数是color参数color = args[0]print(f'一盒{color}泡沫球')else:print(f'一盒泡沫球')print('好多巧克力')print('一支dior口红')result = gift(*args, **kwargs)  # 如果我们需要对原函数的结果做出处理,可以先获取到结果# print(f'原函数结果{result}')    由于原函数gift没有return,这是其实是Nonereturn result  # 返回原函数结果return new_gift @box
def gift(color, pro=False):   # 新的礼物函数,两个参数,默认买12,万一女友要Pro,也可以if pro is True:print(f'iPhone12 Pro{color}版')else:print(f'iPhone12{color}版')gift('海蓝色', pro=True)

这样,无论被装饰的函数有几个参数,box装饰器都可以正常处理。
运行后显示如下。

=====礼物盒=====
一盒海蓝色泡沫球
好多巧克力
一支dior口红
iPhone12 Pro海蓝色版

带参装饰器
信心满满的小李觉得,在盒子上还可以做些文章,要根据女友的喜好选择不同形状的箱子,因此我们需要根据参数来定制我们的装饰器box,在盒子外面再加一层定制函数。

def custom_box(shape):   # 根据参数定制装饰器def box(gift):   # 装饰器函数print('='*5 + f'{shape}礼物盒' + '='*5)   # 根据形状定制# ...return box   # 返回装饰器函数

此时我们得到一个可以根据参数进行定制的装饰器函数custom_box,这个装饰器接收到参数后,传递给真实装饰器box,并返回定制后box装饰器函数。
完整代码如下。

def custom_box(shape):   # 根据参数定制装饰器 =====================def box(gift):   # 实际的装饰器函数 ---------------------------print('='*5 + f'{shape}礼物盒' + '='*5)def new_gift(*args, **kwargs):   # 傀儡函数 ..............if args and len(args) > 0:color = args[0]print(f'一盒{color}泡沫球')else:print(f'一盒泡沫球')print('好多巧克力')print('一支dior口红')result = gift(*args, **kwargs)return result  # 返回原函数结果 ......................return new_gift # 返回傀儡函数 ---------------------------return box   # 返回定制的装饰器 ===============================@custom_box('心形')   # 使用可定制的装饰器
def gift(color, pro=False):   if pro is True:print(f'iPhone12 Pro{color}版')else:print(f'iPhone12{color}版')gift('海蓝色', pro=True)

注意:装饰器在导入模块时立即计算的,即没调用gift(‘海蓝色’, pro=True)之前就已经执行生成定制后的box。

运行后,结果如下。

=====心形礼物盒=====
一盒海蓝色泡沫球
好多巧克力
一支dior口红
iPhone12 Pro海蓝色版

理解 Python 中的装饰器相关推荐

  1. [转载]理解PYTHON中的装饰器

    [翻译]理解PYTHON中的装饰器 来源stackoverflow上的问题 链接 python的函数是对象 要理解装饰器,首先,你必须明白,在python中,函数是对象. 这很重要. 简单例子来理解为 ...

  2. python装饰器作用-理解python中的装饰器

    一 什么是装饰器? 正如其名,装饰器的作用是为已经存在的对象增加额外功能(装饰),由此可使已有函数在无需代码改动的情况下增加额外功能:装饰器的本质是嵌套的函数且返回函数对象,即闭包.有关闭包的概念,可 ...

  3. python装饰器原理-python 中的装饰器及其原理

    装饰器模式 此前的文章中我们介绍过装饰器模式: 装饰器模式中具体的 Decorator 实现类通过将对组建的请求转发给被装饰的对象,并在转发前后执行一些额外的动作来修改原有的部分行为,实现增强 Com ...

  4. 为什么说想到Python中的装饰器是天才

    为什么说想到Python中的装饰器是天才 只需一个@符号就能分析.测试和重复使用你的代码 带着魔杖的仙女在Python代码中飞舞 软件中有没有什么是神奇的小魔法? 有,装饰器却非常接近! 如果说有一件 ...

  5. python类装饰器详解-python 中的装饰器详解

    装饰器 闭包 闭包简单的来说就是一个函数,在该函数内部再定义一个函数,并且这个内部函数用到了外部变量(即是外部函数的参数),最终这个函数返回内部函数的引用,这就是闭包. def decorator(p ...

  6. python中的装饰器decorator

    python中的装饰器 装饰器是为了解决以下描述的问题而产生的方法 我们在已有的函数代码的基础上,想要动态的为这个函数增加功能而又不改变原函数的代码 例如有三个函数: def f1(x):return ...

  7. python编写装饰器_写python中的装饰器

    python中的装饰器主要用于在已有函数实现功能前附加需要输出的信息,下面将用实例展示我如何写装饰器. 首先分别尝试写装饰器装饰一个无参函数和一个有参函数(被装饰函数仅输出,无返回值情况下) 1 de ...

  8. python中的装饰器(基础装饰器)

    文章目录 一 前置知识-高阶函数,闭包 1. 高阶函数 2. 闭包 二 函数装饰器 1. 什么是装饰器(原理)? 2. 装饰器的实现 3. 何时执行装饰器 4. wraps方法 三 类装饰器 一 前置 ...

  9. python中的装饰器有哪些-python 装饰器以及开发中常用的例子

    有时候我们想为多个函数,同意添加某一种功能,比如及时统计,记录日志,缓存运算结果等等,而又不想改变函数代码 那就定义装饰器函数,用它来生成一个在原函数基础添加了新功能的函数,代替原函数 参考金角大王的 ...

最新文章

  1. 域用户绑定计算机批量设置,Windows 2008 AD域账户与计算机名批量绑定
  2. Normalize.css :一种用于重置默认的CSS样式的样式工具
  3. SQL工作笔记-达梦7中存储过程相关笔记(有参、无参、变量声明)
  4. vue中的静态资源打包
  5. 达梦数据库查询表结构
  6. 数学第一单元计算机思维导图,七年级下册数学第一单元思维导图
  7. C语言段错误-core文件
  8. scratch python的区别ev3_机器人编程和少儿编程,傻傻分不清—乐高EV3入门感想
  9. 2节串联锂电池充电管理IC芯片,5V,12V升降压解决方案
  10. 收藏 | 江苏省各地教师公务员等实际工资爆料
  11. 服务器cpu开启虚拟化的好处,开启硬件虚拟化有什么好处和坏处?
  12. 微信登录+sdk+服务器,微信sdk后端集成
  13. 现网必用的主备冗余技术,VRRP理论+配置
  14. 《墨宝非宝经典作品合集(套装共10册)》墨宝非宝(作者)epub+mobi+azw3格式下载...
  15. 睡眠伤害计算机硬件吗,电脑长时间睡眠、不关机对电脑有伤害吗?
  16. 百度智能云 API鉴权总结
  17. Windows10+ubuntu 双系统安装(针对联想小新air14)
  18. 【ACWing】1063. 永无乡
  19. 管理信息系统期末复习资料
  20. 第三章 事件 windows程序设计 王艳平版

热门文章

  1. 阿克曼前轮转向车gazebo模型
  2. php账单明细功能怎么实现,PHP实现微信优势对账单处理
  3. MySQL更新时间的时候生成随机时间
  4. 开源项目——小Q聊天机器人V1.1
  5. 关于ST的一些库的说明(附标准库下载地址)
  6. 微软云中国的服务器在哪,微软云计算平台Windows Azure将落户中国
  7. HDU 6069 Counting Divisors
  8. hdu 6069 区间筛
  9. linkedin解封_LinkedIn信号:Scala,JRuby和Voldemort的案例研究
  10. Cadence 简易使用教程