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

Python 函数装饰器和闭包(使用装饰器改进“策略”模式)

本章内容:
Python 如何计算装饰器句法
Python 如何判断变量是不是局部的
闭包存在的原因和工作原理
nonlocal 能解决什么问题
掌握这些基础知识后,我们可以进一步探讨装饰器:
实现行为良好的装饰器
标准库中有用的装饰器
实现一个参数化装饰器

使用装饰器改进“策略”模式

使用注册装饰器可以改进 6.1 节中的电商促销折扣示例。

回顾一下,示例 6-6 的主要问题是,定义体中有函数的名称,但是
best_promo 用来判断哪个折扣幅度最大的 promos 列表中也有函数名
称。这种重复是个问题,因为新增策略函数后可能会忘记把它添加到
promos 列表中,导致 best_promo 忽略新策略,而且不报错,为系统
引入了不易察觉的缺陷。示例 7-3 使用注册装饰器解决了这个问题。

示例 7-3 promos 列表中的值使用 promotion 装饰器填充

promos = [] ➊
def promotion(promo_func): ➋promos.append(promo_func)
return promo_func
@promotion ➌
def fidelity(order):"""为积分为1000或以上的顾客提供5%折扣"""return order.total() * .05 if order.customer.fidelity >= 1000 else 0
@promotion
def bulk_item(order):"""单个商品为20个或以上时提供10%折扣"""discount = 0for item in order.cart:if item.quantity >= 20:discount += item.total() * .1return discount
@promotion
def large_order(order):"""订单中的不同商品达到10个或以上时提供7%折扣"""distinct_items = {item.product for item in order.cart}if len(distinct_items) >= 10:return order.total() * .07return 0
def best_promo(order): ➍
"""选择可用的最佳折扣
"""return max(promo(order) for promo in promos)

❶ promos 列表起初是空的。
❷ promotion 把 promo_func 添加到 promos 列表中,然后原封不动
地将其返回。
❸ 被 @promotion 装饰的函数都会添加到 promos 列表中。
❹ best_promos 无需修改,因为它依赖 promos 列表。
与 6.1 节给出的方案相比,这个方案有几个优点。

  • 促销策略函数无需使用特殊的名称(即不用以 _promo 结尾)。
  • @promotion 装饰器突出了被装饰的函数的作用,还便于临时禁用
    某个促销策略:只需把装饰器注释掉。
  • 促销折扣策略可以在其他模块中定义,在系统中的任何地方都行,
    只要使用 @promotion 装饰即可。

不过,多数装饰器会修改被装饰的函数。通常,它们会定义一个内部函
数,然后将其返回,替换被装饰的函数。使用内部函数的代码几乎都要
靠闭包才能正确运作。为了理解闭包,我们要退后一步,先了解 Python
中的变量作用域。

http://www.xdnf.cn/news/3620.html

相关文章:

  • 玩转Docker | 使用Docker部署AI证件照工具
  • 【2025】ORM框架是什么?有哪些常用?Mybatis和Hibernate是什么样的?
  • ES6/ES11知识点
  • wpf CommandParameter 传递MouseWheelEventArgs参数 ,用 MvvmLight 实现
  • Word域操作记录(从1开始的毕业论文格式排版)
  • 神经网络的基本概念与深度解析——基于生物机制的仿生建模与工程实现
  • Spring Boot的GraalVM支持:构建低资源消耗微服务
  • Kubernetes(k8s)学习笔记(四)--入门基本操作
  • 双指针(5)——有效三角形个数
  • 杭电oj(1180、1181)题解
  • “淘宝闪购”提前4天全量,意味着什么?
  • 传奇各职业/战士/法师/道士/手套/手镯/护腕/神秘腰带爆率及出处产出地/圣战/法神/天尊/祈祷/虹魔/魔血
  • Demo02_基于寄存器+标准库开发的项目
  • 传奇各职业/战士/法师/道士/戒指爆率及出处产出地/圣战/法神/天尊/虹魔/魔血/麻痹/超负载/求婚/隐身/传送/复活/护身/祈祷/火焰
  • Linux系统常用命令、标准C库函数和系统调用
  • new和malloc的区别
  • 一场陟遐自迩的 SwiftUI + CoreData 性能优化之旅(上)
  • Redis总结及设置营业状态案例
  • 泰迪杯特等奖案例学习资料:基于CLIP模型微调与知识蒸馏的多模态图文检索系统设计
  • B站Michale_ee——ESP32_IDF SDK——FreeRTOS_7 流数据缓冲区、消息缓冲区
  • Python基于深度学习的网络舆情分析系统(附源码,部署)
  • 基于蒙特卡洛模拟的电路容差分析与设计优化
  • 倒排索引与数据库索引
  • 拆解一个550-800Mhz的LC滤波器内部大图配测试曲线
  • 这款软件的第三方评测:功能、易用性与性能表现如何?
  • 链表系列一> K 个一组翻转链表
  • wsl安装
  • 自动化测试项目2 --- 比特纵横 [软件测试实战 Java 篇]
  • 泰迪杯特等奖案例学习资料:基于时空图卷积网络的结构健康监测数据异常识别系统
  • OrbitControls