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

Python函数式编程进阶:用函数实现设计模式

文章目录

  • 函数式编程进阶:用函数实现设计模式
    • 案例实现:构建“策略”模式
      • 使用函数实现”策略“模式
        • 享元
      • 选择最佳策略:简单的方式
    • globals关键字

函数式编程进阶:用函数实现设计模式

案例实现:构建“策略”模式

策略模式:我们把一系列算法封装起来,使得他们可以相互替换,本模式可以独立于他们的客户而变化

from abc import ABC, abstractmethod
from collections import namedtupleCustomer = namedtuple("Customer",'name fidelity')class LineItem:def __init__(self,product,quantity,price) -> None:self.product = productself.quantity = quantityself.price = pricedef total(self):return self.quantity * self.priceclass Order: # 上下文def __init__(self, customer, cart, promotion=None) -> None:self.customer = customerself.cart = list(cart)self.promotion = promotiondef total(self):if not hasattr(self,'__total'):self.__total = sum(item.total() for item in self.cart)return self.__totaldef due(self):if self.promotion is None:discount = 0else:discount = self.promotion.discount(self)return self.total() - discountdef __repr__(self) -> str:fmt = '<Order total: {:.2f} due: {:.2f}'return fmt.format(self.total,self.due)class Promotion(ABC): #抽象基类@abstractmethoddef discount(self, order):"""返回折扣金额"""class FidelityPromo(Promotion):def discount(self, order):"""积分为1000以上的顾客提供5%的折扣"""return order.total() * .05 if order.customer.fidelity >= 1000 else 0class BulkItemPromo(Promotion):def discount(self,order):"""单个商品为20个或以上时提供10%折扣"""discount = 0 for item in order.cart:if item.quantity >= 20:discount += item.total() * .10return discountclass LargeOrderPromo(Promotion):"""订单中的不同商品达到10个以上时提供7%折扣"""def discount(self,order):discount = 0for item in order.cart:if item.quantity >= 10:discount += item.total() * .07return discount

这个实例中我们实例化了所有的策略,还有客户订单,使用抽象基类和抽象方法装饰符来明确所用的方式。

测试以上用例

joe = Customer('John Doe', 0)
ann = Customer('Ann Smith',1000)
cart = [LineItem('banana',4,.5),LineItem('apple',10,1.5),LineItem('watermelon',5,5.0)]order_joe = Order(joe,cart,FidelityPromo())
order_ann = Order(ann,cart,FidelityPromo())
print(repr(order_ann))
print(repr(order_joe))
# 输出
# <Order total: 42.00 due: 39.90>
# <Order total: 42.00 due: 42.00>

使用函数实现”策略“模式

以上实例都是基于类实现的,而且每个类都只定义了一个方法,而且每个实例都没有自己的状态,看起来和普通的函数没有区别

我们可以把具体策略换成函数实现

from abc import ABC, abstractmethod
from collections import namedtupleCustomer = namedtuple("Customer",'name fidelity')class LineItem:def __init__(self,product,quantity,price) -> None:self.product = productself.quantity = quantityself.price = pricedef total(self):return self.quantity * self.priceclass Order: # 上下文def __init__(self, customer, cart, promotion=None) -> None:self.customer = customerself.cart = list(cart)self.promotion = promotiondef total(self):if not hasattr(self,'__total'):self.__total = sum(item.total() for item in self.cart)return self.__totaldef due(self):if self.promotion is None:discount = 0else:discount = self.promotion(self)return self.total() - discountdef __repr__(self) -> str:fmt = '<Order total: {:.2f} due: {:.2f}>'return fmt.format(self.total(),self.due())def fidelity_promo(order):"""积分大于1000给予5%的折扣"""return order.total() * .05 if order.customer.fidelity >= 1000 else 0def bulk_item_promo(order):"""单个商品20个以上提供10%的折扣"""discount = 0 for item in order.cart:if item.quantity >= 20:discount += item.total() * .1return discountdef large_order_promo(order):"""订单中不同商品的个数达到10个以上时提供7%的折扣"""distinct_item = {item.product for item in order.cart}if len(distinct_item >= 10):return order.total() * .07return 0joe = Customer('John Doe', 0)
ann = Customer('Ann Smith',1000)
cart = [LineItem('banana',4,.5),LineItem('apple',10,1.5),LineItem('watermelon',5,5.0)]order_joe = Order(joe,cart,fidelity_promo)
order_ann = Order(ann,cart,fidelity_promo)
print(repr(order_ann))
print(repr(order_joe))

把折扣策略通过函数实现可以减少一部分的代码量,但是以上两种办法,都没有办法实现最佳调用方法,它们缺少内部状态

这些具体策略都没有内部状态,只是单纯的对上下文进行处理

这个时候需要引入享元的做法

享元

享元是可以共享的对象,同时可以在多个上下文中使用,这样不必再新的上下文中根据不同策略不断创建新的实例对象

选择最佳策略:简单的方式

promos = [fidelity_promo,bulk_item_promo,large_order_promo]
def best_promo(order):return max(promo(order) for promo in promos)

以上代码可用但是如果添加新的方法就需要把他加到promos列表中否则best_promo函数不会考虑新的策略,要如何保证新加的策略立刻就能应用到bestpromo函数呢

globals关键字

globals()是python的一个内置方法,表示当前的全局符号表.

比如当我在程序运行最后打印这个关键字,其返回值是一个字典

{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000234CBDD6CD0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'c:\\Users\\Administrator\\GithubRepo\\study_recording\\fluent_python\\ch06_07\\functional_pattern_design.py', '__cached__': None, 'ABC': <class 'abc.ABC'>, 'abstractmethod': <function abstractmethod at 0x00000234CC2780D0>, 'namedtuple': <function namedtuple at 0x00000234CC466550>, 'Customer': <class '__main__.Customer'>, 'LineItem': <class '__main__.LineItem'>, 'Order': <class '__main__.Order'>, 'fidelity_promo': 
<function fidelity_promo at 0x00000234CC486DC0>, 'bulk_item_promo': <function bulk_item_promo at 0x00000234CC4881F0>, 'large_order_promo': <function large_order_promo at 0x00000234CC488280>, 'promos': [<function fidelity_promo at 0x00000234CC486DC0>, <function bulk_item_promo at 0x00000234CC4881F0>, <function large_order_promo at 0x00000234CC488280>], 'best_promo': <function best_promo at 0x00000234CC488310>, 'joe': Customer(name='John Doe', fidelity=0), 'ann': Customer(name='Ann Smith', fidelity=1000), 'cart': [<__main__.LineItem object at 0x00000234CC281430>, <__main__.LineItem object at 0x00000234CC2D66A0>, <__main__.LineItem object at 0x00000234CC2D68E0>], 'banana_cart': [<__main__.LineItem object at 0x00000234CC2D62E0>, <__main__.LineItem object at 0x00000234CC2D63A0>], 'order_joe': <Order total: 42.00 due: 42.00>, 'order_ann': <Order total: 42.00 due: 39.90>, 'banana_order_joe': <Order total: 30.00 due: 28.50>, 'banana_order_ann': <Order total: 30.00 due: 28.50>}

可以利用这个全局符号表来帮我们找到一些刚创建的策略

promos = [globals()[name] for name in globals()if name.endswith('_promo')and name != 'best_promo'] # 防止递归
def best_promo(order):return max(promo(order) for promo in promos)

相关文章:

Python函数式编程进阶:用函数实现设计模式

文章目录 函数式编程进阶&#xff1a;用函数实现设计模式案例实现&#xff1a;构建“策略”模式使用函数实现”策略“模式享元 选择最佳策略&#xff1a;简单的方式 globals关键字 函数式编程进阶&#xff1a;用函数实现设计模式 案例实现&#xff1a;构建“策略”模式 策略模…...

Ingress controller:Kubernetes 的瑞士军刀

原文作者&#xff1a;Brian Ehlert of F5 原文链接&#xff1a;Ingress controller&#xff1a;Kubernetes 的瑞士军刀 转载来源&#xff1a;NGINX 中文官网 NGINX 唯一中文官方社区 &#xff0c;尽在 nginx.org.cn 许多人认为 Ingress controller&#xff08;Ingress 控制器&…...

uniapp tabBar app页面滚动闪屏的问题

我在做app的时候&#xff0c;调试tabBar页面滚动时莫名其妙的闪屏&#xff0c;其他页面不闪屏&#xff0c;可能跟新建的项目样式有关。 修改方法如下。 在pages.json中 "tabBar": {"selectedColor": "#204AFF","color": "#ccc…...

【计算机毕业设计】388微信小程序足球赛事及队伍管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…...

监控易监测对象及指标之:华为FusionInsight Kafka服务全方位监控

监控易提供对华为FusionInsight Kafka服务的全方位监控功能。该功能可以帮助用户实时监测Kafka服务的各项性能指标&#xff0c;确保服务的稳定运行和高效性能。 具体功能点包括&#xff1a; 服务状态监测&#xff1a;监控易能够实时监测华为FusionInsight Kafka服务的运行状态…...

Python装饰器的应用

Python 中的装饰器是一种语法糖&#xff0c;可以在运行时&#xff0c;动态的给函数或类添加功能。装饰器本质上是一个函数&#xff0c;使用 函数名就是可实现绑定给函数的第二个功能 。它的作用就是在不修改被装饰对象源代码和调用方式的前提下为被装饰对象添加额外的功能。 …...

【数据结构与算法 | 基础篇】力扣232, 225

1. 力扣232 : 用栈实现队列 (1). 题 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a; 实现 MyQueue 类&#xff1a; void push(int x) 将元素 x 推到队列的末尾int pop() 从队列的开头移…...

内网(极空间)搭建gitlab跳板机转发端口及域名配置

背景说明 https://blog.csdn.net/GodDavide/article/details/139182475 上文说到: 我已经用docker搭好了gitlab-ce服务&#xff0c;但我是部署在自己的家庭nas-极空间z4pro里的&#xff0c;属于内网环境。 另外我有一台阿里云服务器&#xff0c;做跳板机。 我有一个阿里的域名…...

如何知道自己电脑的 Shell类型是什么?

在macOS中&#xff0c;你可以通过以下几种方法来确定当前正在使用的shell类型&#xff0c;并了解相关的配置文件&#xff1a; 1. 使用终端命令确定shell类型 打开终端应用程序&#xff08;Terminal&#xff09;。输入以下命令并按回车键&#xff1a;echo $SHELL。该命令会输出…...

Axios的使用简单说明

axios 请求方式和参数 axios 可以发送 ajax 请求&#xff0c;不同的方法可以发送不同的请求: axios.get&#xff1a;发送get请求 axios.post&#xff1a;发送post请求 axios.put&#xff1a;发送put请求 axios.delete&#xff1a;发送delete请求 无论哪种方法&#xff0c;第一…...

查找list集合中,持续时间>=ContinueTime的数据集合,保存在新的list中

在给定的包含时间戳的list中&#xff0c;查找连续continueNum次的且时间间隔为needDiff的集合。 eg&#xff1a;相邻两个数据的时间戳间隔为1分钟&#xff0c;且超过30分钟有数据 /**** param list 包含时间戳&#xff08;10位&#xff09;的list* param continueNum 至少持续…...

nginx 反向代理配置详解

Nginx 反向代理是一种常用的部署策略&#xff0c;用于将客户端请求转发到内部网络中的一个或多个服务器&#xff0c;这些服务器直接处理请求并返回响应给Nginx&#xff0c;再由Nginx转交给客户端。这种设置可以提高网站的可用性和安全性&#xff0c;同时也能实现负载均衡、缓存…...

微信小程序毕业设计-农场驿站平台系统项目开发实战(附源码+论文)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计…...

CAN总线应用协议CANopen

作为一种真正开放的CAN总线高层协议&#xff0c;CANopen协议允许不同的CAN设备以标准化的方式进行通讯&#xff0c;这使得CAN 设备具有互操作性。随着CANopen协议的日益完善&#xff0c;它已经广泛应用于多个行业。本文将对CANopen协议的对象字典、通讯对象、网络管理等几个方面…...

htop安装不了怎么解决

&#x1f31f;&#x1f30c; 欢迎来到知识与创意的殿堂 — 远见阁小民的世界&#xff01;&#x1f680; &#x1f31f;&#x1f9ed; 在这里&#xff0c;我们一起探索技术的奥秘&#xff0c;一起在知识的海洋中遨游。 &#x1f31f;&#x1f9ed; 在这里&#xff0c;每个错误都…...

vue 笔记02

目录 01 事件修饰符 02 按键修饰符 03 v-bind属性 04 vue-axios的基本使用 05 vue的生命周期 06 vue生命周期涉及到的其他的知识点 01 事件修饰符 vue的事件修饰符 事件名称.修饰符1.修饰符2...事件驱动函数 stop 阻止冒泡修饰符 prevent 阻止默认行为 once 当前事件只触…...

MySQL8.0免安装及phpmyadmin配置

安装包解压&#xff0c;运行mysqld文件后&#xff0c;启动net start&#xff0c;提示成功&#xff0c;但进入phpmyadmin登录页面后&#xff0c;输入用户名&#xff0c;提示不支持空密码&#xff0c;config.default.php设置密码后&#xff0c;提示 mysqli::real_connect(): (HY…...

【目标解算】相机内外参数详细解读+坐标系转换

一、相机参数介绍 1.1 相机内参矩阵 概念&#xff1a;内参矩阵用于描述相机的内部参数&#xff0c;它包含了相机的焦距、主点坐标和图像的畸变等信息。内参矩阵的形式通常为一个3x3的矩阵&#xff0c;常用表示为K。内参矩阵可以将相机坐标系中的三维点映射到图像平面上的二维…...

【Unity】颜色混合计算

在图形渲染中&#xff0c;颜色混合&#xff08;Color Blending&#xff09;是指将多个颜色值组合在一起以生成最终显示的颜色。颜色混合技术广泛用于处理半透明效果、光照效果和后期处理效果。以下是一些常见的颜色混合模式&#xff1a; 1. 正常混合&#xff08;Normal Blendi…...

Vue源码解析

入门级 <body><div id"app"></div><script>class Vue {constructor(options) {// thisVue 把options.created的this 指向Vue实例options.created.bind(this)();// this.$el 指向#appthis.$el document.querySelector(options.el);// 把opt…...

Linux---网络相关配置

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 一台主机需要配置必要的网络信息&#xff0c;才可以连接到互联网&#xff0c;需要的配置网络信息包括IP&#xff0c;子网掩码&#xff0c;网关和DNS。 一.查看网络信息 查看IP信息可以通…...

MATLAB分类与判别模型算法:基于Fisher算法的分类程序【含Matlab源码 MX_002期】

算法思路介绍&#xff1a; 费舍尔线性判别分析&#xff08;Fishers Linear Discriminant Analysis&#xff0c;简称 LDA&#xff09;&#xff0c;用于将两个类别的数据点进行二分类。以下是代码的整体思路&#xff1a; 生成数据&#xff1a; 使用 randn 函数生成随机数&#x…...

长文总结 | Python基础知识点,建议收藏

测试基础-Python篇 基础① 变量名命名规则 - 遵循PEP8原则 普通变量&#xff1a;max_value 全局变量&#xff1a;MAX_VALUE 内部变量&#xff1a;_local_var 和关键字重名&#xff1a;class_ 函数名&#xff1a;bar_function 类名&#xff1a;FooClass 布尔类型的变量名…...

centos中使用Docker安装rabbitmq记录

一、安装rabbitmq docker run -d --name rabbitmq -p 5672:5672 -p15672:15672 -v rabbitmq-plugin:/plugins -e RABBITMQ_DEFAULT_USERxiaoqi -eRABBITMQ_DEFAULT_PASS123456 rabbitmq:latest二、配置web管理界面 # 查看运行的容器 docker ps -a # 根据容器id进入容器内部 …...

STM32系列-STM32介绍

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” STM32介绍 STM32介绍 ST&#xff1a;指的是意法半导体 M&#xff1a;指定微处理器 32&#xff1a;表示计算机处理器位数 ARM分成三个系列&#xff1a; Cortex-A&#xff1…...

网络原理 一

一、协议 网络通信中,协议是非常重要的概念. 协议进行了分层,此处就是按照这几层顺序来介绍每一层中的核心协议. 应用层,就对应着应用程序,是程序员打交道最多的一层,调用系统提供的 网络api 写出的代码都是基于应用层的. 应用层这里当然也有很多现成的协议,但更多的还是,程…...

xcode配置快速打开终端命令行工具教程

以往我们使用idea编辑器或者vscode编辑器的时候&#xff0c;我们可以快速的在编辑器下面打开终端进行相关的操作&#xff0c;但是在xcode里面却没有这么方便的功能按钮&#xff0c;真的不是很习惯&#xff0c;所以这次就来给xcode配置这么一个方便的功能。 idea的Terminal 这…...

AIGC降重:如何2分钟降低论文AI率和查重率?推荐使用SpeedAI科研小助手

确保学术论文的独立性与诚信性&#xff0c;对于学业的成就及学位的获取至关重要&#xff0c;其中&#xff0c;论文的人工智能查重与降低AIGC相似度扮演着核心角色。 常规的查重手段主要围绕查重软件的运用和个体的自行审查&#xff1b;而降重则通常通过语句重组、同义替换、内…...

Blazor入门-连接MySQL的简单例子:列出数据+简单查询

参考&#xff1a; ASP.NET Core 6.0 Blazor Server APP并使用MySQL数据库_blazor mysql-CSDN博客 https://blog.csdn.net/mzl87/article/details/129199352 本地环境&#xff1a;win10, visual studio 2022 community, mysql 8.0.33 (MySQL Community Server), net core 6.0 目…...

CEEMDAN +组合预测模型(CNN-Transfromer + XGBoost)

注意&#xff1a;本模型继续加入 组合预测模型全家桶 中&#xff0c;之前购买的同学请及时更新下载! 往期精彩内容&#xff1a; 时序预测&#xff1a;LSTM、ARIMA、Holt-Winters、SARIMA模型的分析与比较-CSDN博客 VMD CEEMDAN 二次分解&#xff0c;Transformer-BiGRU预测模…...