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)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/18962.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/18962.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/18962.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java 18新特性:探索Java的未來

目錄 1. 增強的模式匹配 2. JEP 411&#xff1a;String解構 3. JEP 395&#xff1a;Records增強 4. JEP 398&#xff1a;Deprecate警告增強 5. JEP 409&#xff1a;Sealed類和接口增強 6. API改進 6.1 集合API改進 6.2 流API改進 6.3 IO/NIO API改進 7. 性能優化 7.…

從0開始帶你成為Kafka消息中間件高手---第三講

從0開始帶你成為Kafka消息中間件高手—第三講 實際上來說&#xff0c;每次leader接收到一條消息&#xff0c;都會更新自己的LEO&#xff0c;也就是log end offset&#xff0c;把最后一位offset 1&#xff0c;這個大家都能理解吧&#xff1f;接著各個follower會從leader請求同…

k8s 中svc映射的外部端口是如何監聽的,netstat命令為什么查不到?

在Kubernetes中&#xff0c;Service&#xff08;服務&#xff09;是一種抽象&#xff0c;用于將一組Pod&#xff08;容器&#xff09;公開為一個網絡服務。Service可以通過ClusterIP&#xff08;集群內部IP&#xff09;、NodePort&#xff08;節點端口&#xff09;或LoadBalanc…

KDD 2024|基于隱空間因果推斷的微服務系統根因定位

簡介&#xff1a;本文介紹了由清華大學、南開大學、eBay、微軟、中國科學院計算機網絡信息中心等單位共同合作的論文《基于隱空間因果推斷的受限可觀測性場景的微服務系統根因定位》。該論文已被KDD 2024會議錄用。 論文標題&#xff1a;Microservice Root Cause Analysis Wit…

10年老運營人吐血整理,給新媒體運營人的20條建議!沈陽新媒體運營培訓

對于企業&#xff0c;在新媒體平臺開設官方賬號應該是已經成為標配。不僅是對企業新媒體運營需求量提高&#xff0c;新媒體人的薪資也是水漲船高。 另外值得注意的是&#xff0c;企業對資深新媒體運營人才尤為重視&#xff0c;這表現在他們不惜重金招聘高薪新媒體運營人才&…

Linux新增磁盤掛載分區

1. 查看磁盤分區名稱 lsblk 可見&#xff0c;新增的分區為 sdb 2.格式化磁盤 mkfs.xfs -f /dev/sdb 3.掛在磁盤到 /ocean目錄&#xff0c;掛在前先創建空目錄 /ocean mkdir /oceanmount /dev/sdb /ocean 執行后&#xff0c;可用 df -h 查看分區是否成功 4.持久化磁盤分區&a…

查詢MongoDB中某個數據庫的占用空間大小

要查詢MongoDB中某個數據庫的占用空間大小&#xff0c;可以使用以下幾種方法&#xff1a; 方法一&#xff1a;使用 MongoDB Shell (mongo) 1. **連接到 MongoDB**&#xff1a; bash mongo 2. **選擇數據庫**&#xff1a; javascript use yourDatabaseName …

AI推介-大語言模型LLMs論文速覽(arXiv方向):2024.05.20-2024.05.25

文章目錄~ 1.STRIDE: A Tool-Assisted LLM Agent Framework for Strategic and Interactive Decision-Making2. M 3 M^3 M3GPT: An Advanced Multimodal, Multitask Framework for Motion Comprehension and Generation3.MindStar: Enhancing Math Reasoning in Pre-trained LL…

計算機圖形學入門03:二維變換

變換(Transformation)可分為模型(Model)變換和視圖(Viewing)變換。在3D虛擬場景中相機的移動和旋轉&#xff0c;角色人物動畫都需要變換&#xff0c;用來描述物體運動。將三維世界投影變換到2D屏幕上成像出來&#xff0c;也需要變換。 1.縮放變換 縮放(Scale)變換&#xff1a; …

【B站 heima】小兔鮮Vue3 項目學習筆記 Day06

文章目錄 購物車本地1. 列表購物車基礎數據渲染2. 列表購物車單選功能3. 列表購物車全選功能4. 列表購物車統計列表實現5. 接口-加入購物車6. 接口-刪除購物車7. 退出登錄-清空購物車數據8. 合并購物車到服務器(重要) 結算1. 路由配置和基礎數據渲染2. 地址切換-打開彈框交互實…

跨境人必讀:X(原Twitter)和Facebook區別是什么?

在今日全球化的商業環境中&#xff0c;跨境電商領域的企業和獨立站賣家正逐漸認識到社交媒體營銷的巨大潛力。特別是X&#xff08;原Twitter&#xff09;和Facebook&#xff0c;作為領先的社交媒體平臺&#xff0c;它們的使用不僅能夠提升品牌知名度&#xff0c;還能直接影響銷…

基于Java實現的圖書管理系統

前言&#xff1a;該圖書管理系統實現了查找、添加、刪除、顯示、借閱、歸還等功能&#xff0c;分為兩個用戶群體&#xff1a;管理者和普通用戶。使用了類與對象&#xff0c;封裝繼承多態&#xff0c;抽象類和接口等Java基礎知識。 一.思路 面向對象三部曲&#xff1a;找對象&…

oracle數據庫查看各類文件的位置

select name from v$controlfile; --控制文件 &#xff08;一般以.ctl結尾&#xff09; select file_name from dba_data_files; --數據文件 &#xff08;一般以.dbf或.ora結尾&#xff09; select file_name from dba_temp_files; --臨時文件&#xff08;一般以.d…

OrangePi_Kunpeng_Pro開發板測驗——性能巨人

文章目錄 &#x1f4d1;前言一、開箱初體驗的愉悅二、產品規格概述三、前置工作四、性能測試4.1 CPU 性能測試4.1.1 單線程 CPU 測試4.1.2 多線程 CPU 測試 4.2 內存性能測試4.2.1 內存讀寫性能測試4.2.2 高負載內存測試 4.3 I/O 性能測試4.4 網絡性能測試4.5 測試小結4.5.1 CP…

ECMAScript簡介

前言 ECMAScript&#xff08;通常簡稱為ES&#xff09;由ECMA國際標準化組織制定的一種腳本語言標準&#xff0c;Netscape最初開發的JavaScript演變而來。ECMAScript為JavaScript提供了基礎語言結構和功能。最初設計成一種腳本語言&#xff0c;用來服務Web。作為腳本語言ES同時…

CF1148C C. Crazy Diamond

題目鏈接 題意&#xff1a;給定一個數組p長度為n按照規則對下標滿足2 * abs(i - j) > n進行交換&#xff0c;最后使數組不遞減。輸出用的交換次數和每次交換的下標。&#xff08;交換次數不能超過5*n次&#xff09; 題解&#xff1a; 默認i < j,否則交換 abs(i - j) &…

基于異構圖的大規模微服務系統性能問題診斷

簡介&#xff1a;本文介紹由南開大學、清華大學、騰訊、國家超級計算天津中心共同合作的論文&#xff1a;基于異構圖的大規模微服務系統性能問題診斷。該論文已被IEEE Transactions on Services Computing期刊錄用 論文標題&#xff1a;Diagnosing Performance Issues for Lar…

docker刪除所有容器

筆記 要使用 Docker 刪除所有容器&#xff08;無論是停止的還是正在運行的&#xff09;&#xff0c;可以按照以下步驟操作&#xff1a; 1. **刪除所有正在運行的容器**&#xff1a; 首先&#xff0c;您需要停止所有正在運行的容器。可以使用以下命令&#xff1a; dock…

MATLAB分類與判別模型算法:K-近鄰法(KNN)分類代碼 【含Matlab源碼 MX_001期】

算法簡介&#xff1a; K-近鄰法&#xff08;KNN&#xff09;是一種簡單而有效的分類算法&#xff0c;也可用于回歸問題。它的基本原理是根據待分類樣本與訓練樣本的距離&#xff0c;選取最近的K個樣本進行投票決定分類。該算法無需訓練過程&#xff0c;而是利用訓練數據集直接…

數據結構與算法-反轉單鏈表

數據結構與算法-反轉單鏈表 大家好&#xff0c;歡迎回到我們的算法學習系列。今天&#xff0c;我們將探討一個在算法面試中非常經典的問題——反轉單鏈表。 什么是單鏈表&#xff1f; 在介紹問題之前&#xff0c;我們先簡單了解一下單鏈表。單鏈表是一種線性數據結構&#x…