python[進階] 6.使用一等函數實現設計模式

文章目錄

    • 6.1.1 經典的“策略”模式
    • 6.1.2 使用函數實現“策略”模式
    • 6.1.3 選擇最佳策略:簡單的
    • 6.1.4 找出模塊中的全部
  • 6.2 “命令”模式

6.1.1 經典的“策略”模式

為抽象基類(Abstract Base Class,ABC),這么做是為了使用 @abstractmethod 裝飾器
來個例子:

from abc import ABC, abstractmethod
from collections import namedtuple
Customer = namedtuple('Customer', 'name fidelity')
class LineItem:def __init__(self, product, quantity, price):self.product = productself.quantity = quantityself.price = pricedef total(self):return self.price * self.quantityclass Order: #上下文def __init__(self, customer, cart, promotion=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):fmt = '<Order total: {:.2f} due: {:.2f}>'return fmt.format(self.total(), self.due())
class Promotion (ABC): #抽象基類@abstractmethoddef discount(self, order):""""返回折扣金額"""class FidelityPromo(Promotion):#第一個具體策略"""為積分為1000或者以上的的顧客提供5%折扣"""def discount(self, order):return order.total() * 0.05 if order.customer.fidelity >= 1000 else 0class BulkItemPromo(Promotion):#第二個具體策略"""單個商品為20個或以上時提供10%折扣"""def discount(self, order):discount = 0for item in order.cart:if item.quantity >= 20:discount += item.total() *0.1return discountclass LargeOrderPromo(Promotion):#第三個具體策略"""訂單中的不同商品達到10個或者以上時提供7%折扣"""def discount(self, order):distinct_items = {item.product for item in order.cart}if len(distinct_items) >= 10:return order.total() * 0.07return 0if __name__ == '__main__':joe = Customer('John Doe', 0)ann = Customer('Ann Smith', 1000)cart = [LineItem('banana', 4, 0.5),LineItem('apple', 10, 1.5),LineItem('watermellon', 5, 5.0)]print(Order(joe, cart, FidelityPromo()))   # <Order total: 42.00 due: 42.00>print(Order(ann, cart, FidelityPromo()))   #<Order total: 42.00 due: 39.90>banana_cart = [LineItem('banana', 30, 0.5),LineItem('apple', 10, 1.5)]print(Order(joe, banana_cart, BulkItemPromo())) #<Order total: 30.00 due: 28.50>long_order = [LineItem(str(item_code), 1, 1.0) for item_code in range(10)]print(Order(joe, long_order, LargeOrderPromo()))  #<Order total: 10.00 due: 9.30>print(Order(joe, cart, LargeOrderPromo())) #<Order total: 42.00 due: 42.00>

上下文 - 把一些計算委托給實現不同算法的可互換組件,它提供服務。在這個電商示例中,上下文是 Order,它會根據不同的算法計算促銷折扣。
策略 - 實現不同算法的組件共同的接口。在這個示例中,名為 Promotion 的抽象類扮演這
個角色。
具體策略 - “策略”的具體子類。fidelityPromo、BulkPromo 和 LargeOrderPromo 是這里實現
的三個具體策略。

6.1.2 使用函數實現“策略”模式

這個例子是對上面的例子 的重構,把具體策略換成了簡單的函數,而且去掉了Promotion 抽象類

from abc import ABC, abstractmethod
from collections import namedtuple
Customer = namedtuple('Customer', 'name fidelity')
class LineItem:def __init__(self, product, quantity, price):self.product = productself.quantity = quantityself.price = pricedef total(self):return self.price * self.quantityclass Order: #上下文def __init__(self, customer, cart, promotion=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):fmt = '<Order total: {:.2f} due: {:.2f}>'return fmt.format(self.total(), self.due())def fidelity_promo(order):"""為積分為1000或者以上的的顧客提供5%折扣"""return order.total() * 0.05 if order.customer.fidelity >= 1000 else 0def bulk_item_promo(order):"""單個商品為20個或以上時提供10%折扣"""discount = 0for item in order.cart:if item.quantity >= 20:discount += item.total() *0.1return discountdef large_order_promo(order):"""訂單中的不同商品達到10個或以上時提供7%折扣"""distinct_items = {item.product for item in order.cart}if len(distinct_items) >= 10:return order.total() * 0.07return 0if __name__ == '__main__':joe = Customer('John Doe', 0)ann = Customer('Ann Smith', 1000)cart = [LineItem('banana', 4, 0.5),LineItem('apple', 10, 1.5),LineItem('watermellon', 5, 5.0)]print(Order(joe, cart, fidelity_promo))   # <Order total: 42.00 due: 42.00>print(Order(ann, cart, fidelity_promo))   #<Order total: 42.00 due: 39.90>banana_cart = [LineItem('banana', 30, 0.5),LineItem('apple', 10, 1.5)]print(Order(joe, banana_cart, bulk_item_promo)) #<Order total: 30.00 due: 28.50>long_order = [LineItem(str(item_code), 1, 1.0) for item_code in range(10)]print(Order(joe, long_order, large_order_promo))  #<Order total: 10.00 due: 9.30>print(Order(joe, cart, large_order_promo)) #<Order total: 42.00 due: 42.00>

? 計算折扣只需調用 self.promotion() 函數。
? 沒有抽象類。
? 各個策略都是函數。
注意示例子中的標注:沒必要在新建訂單時實例化新的促銷對象,函數拿來即用。

  • best_promo 函數計算所有折扣,并返回額度最大的

6.1.3 選擇最佳策略:簡單的

from abc import ABC, abstractmethod
from collections import namedtuple
Customer = namedtuple('Customer', 'name fidelity')
class LineItem:def __init__(self, product, quantity, price):self.product = productself.quantity = quantityself.price = pricedef total(self):return self.price * self.quantityclass Order: #上下文def __init__(self, customer, cart, promotion=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):fmt = '<Order total: {:.2f} due: {:.2f}>'return fmt.format(self.total(), self.due())def fidelity_promo(order):"""為積分為1000或者以上的的顧客提供5%折扣"""return order.total() * 0.05 if order.customer.fidelity >= 1000 else 0def bulk_item_promo(order):"""單個商品為20個或以上時提供10%折扣"""discount = 0for item in order.cart:if item.quantity >= 20:discount += item.total() *0.1return discountdef large_order_promo(order):"""訂單中的不同商品達到10個或以上時提供7%折扣"""distinct_items = {item.product for item in order.cart}if len(distinct_items) >= 10:return order.total() * 0.07return 0promos = [fidelity_promo,bulk_item_promo, large_order_promo]
def best_promo(order):"""選擇可用的最佳折扣"""return max(promo(order) for promo in promos)if __name__ == '__main__':joe = Customer('John Doe', 0)ann = Customer('Ann Smith', 1000)cart = [LineItem('banana', 4, 0.5),LineItem('apple', 10, 1.5),LineItem('watermellon', 5, 5.0)]# print(Order(joe, cart, fidelity_promo))   # <Order total: 42.00 due: 42.00># print(Order(ann, cart, fidelity_promo))   #<Order total: 42.00 due: 39.90>banana_cart = [LineItem('banana', 30, 0.5),LineItem('apple', 10, 1.5)]# print(Order(joe, banana_cart, bulk_item_promo)) #<Order total: 30.00 due: 28.50>long_order = [LineItem(str(item_code), 1, 1.0) for item_code in range(10)]# print(Order(joe, long_order, large_order_promo))  #<Order total: 10.00 due: 9.30># print(Order(joe, cart, large_order_promo)) #<Order total: 42.00 due: 42.00>print(Order(joe, long_order, best_promo))print(Order(joe, banana_cart, best_promo))print(Order(ann, cart, best_promo))

6.1.4 找出模塊中的全部

在 Python 中,模塊也是一等對象,而且標準庫提供了幾個處理模塊的函數。Python 文檔
是這樣說明內置函數 globals 的。

globals() 函數會以字典類型返回當前位置的全部全局變量
例子:

a= "hello"
print(globals())
#{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f0272b221d0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': '/home/maxzhang/PycharmProjects/pythoncode/test.py', '__cached__': None, 'a': 'hello'}

下面的實例 使用 globals 函數幫助 best_promo 自動找到其他可用的 *_promo 函數,過程
有點曲折。

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)

收集所有可用促銷的另一種方法是,在一個單獨的模塊中保存所有策略函數,把
best_promo 排除在外。
在示例 6-8 中,最大的變化是內省名為 promotions 的獨立模塊,構建策略函數列表。注意,示例 6-8 要導入 promotions 模塊,以及提供高階內省函數的 inspect 模塊(簡單起見,這里沒有給出導入語句,因為導入語句一般放在文件頂部)。
示例 6-8 內省單獨的 promotions 模塊,構建 promos 列表,inspect模塊用于收集python對象的信息,可以獲取類或函數的參數的信息,源碼,解析堆棧,對對象進行類型檢查等等。

import inspect
promos = [func for name, func ininspect.getmembers(promotions, inspect.isfunction)]
def best_promo(order):"""選擇可用的最佳折扣"""return max(promo(order) for promo in promos)

inspect.getmembers 函數用于獲取對象(這里是 promotions 模塊)的屬性,第二個
參數是可選的判斷條件(一個布爾值函數)。我們使用的是 inspect.isfunction,只
獲取模塊中的函數。
動態收集促銷折扣函數更為顯式的一種方案是使用簡單的裝飾器。第 7 章討論函數裝飾器
時會使用其他方式實現這個電商“策略”模式示例。

6.2 “命令”模式

“命令”設計模式也可以通過把函數作為參數傳遞而簡化。

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

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

相關文章

2014阿里巴巴校園招聘筆試題 - 中南站

轉載于:https://www.cnblogs.com/gotodsp/articles/3530329.html

python中一些特殊方法的作用

我們先暫且稱呼為特殊方法。 單下劃線開頭&#xff08;_foo&#xff09;雙下劃線開頭的&#xff08;__foo&#xff09;雙下劃線開頭和結尾的&#xff08; __foo__&#xff09;代表不能直接訪問的類屬性&#xff0c;需通過類提供的接口進行訪問&#xff0c;不能用“from xxx im…

Spring的IOC原理[通俗解釋一下]

1. IoC理論的背景 我們都知道&#xff0c;在采用面向對象方法設計的軟件系統中&#xff0c;它的底層實現都是由N個對象組成的&#xff0c;所有的對象通過彼此的合作&#xff0c;最終實現系統的業務邏輯。 圖1&#xff1a;軟件系統中耦合的對象 如果我們打開機械式手表的后蓋&am…

python爬蟲面試遇到的問題

文章目錄&#xff11;python基礎1.1 列表生成式和生成器的區別 &#xff1f;1.2 如何不用任何循環快速篩掉列表中的奇數元素 &#xff1f;1.3 map和reduce的用法1.4 裝飾器的作用1.5 Python中__new__與__init方法的區別1.6 python中的設計模式1.7 lambda函數&#xff0c;以及它…

ubuntu18 常用命令

文章目錄卸載和安裝卸載和安裝 1.打開一個終端&#xff0c;輸入dpkg --list ,按下Enter鍵&#xff0c;終端輸出以下內容&#xff0c;顯示的是你電腦上安裝的所有軟件。 2.安裝 dpkg –i name.deb 安裝一個 deb 包&#xff1b;在終端上輸入命令sudo apt-get --purge remove 包…

以嵌入式系統設計師考試成績,開始嵌入式博客之旅

http://www.rkb.gov.cn/jsj/cms/s_contents/download/s_dt201003110106.html 轉載于:https://www.cnblogs.com/yueqian-scut/p/3952268.html

SSH框架配置及Maven使用

1.SSH框架配置 1.1. SSH框架介紹 1.2. SSH框架配置 所需資源下載&#xff1a; l jdk; 從Oracle官方網站&#xff1a;http://www.oracle.com/technetwork/cn/java/javase/downloads/index.html下載jdk&#xff0c;win7是默認安裝在C:\Program Files (x86)\Java\jdk1.6.0_25路徑下…

cookie,session的區別和聯系(補充token)

文章目錄1 http為什么是無狀態的2 cookie 和session 的區別詳解3 token參考&#xff1a;備注: 博客文章僅限于學習&#xff0c;禁止商用1 http為什么是無狀態的 2 cookie 和session 的區別詳解 這些都是基礎知識&#xff0c;不過有必要做深入了解。先簡單介紹一下。 二者的定…

庫函數和系統調用的區別

前言 這是一對非常容易混淆的概念。對于用戶( 應用程序開發者 )來說&#xff0c;并不一定要嚴格區分其意義。因為在用戶看來&#xff0c;它們都是以C函數的形式出現的。但了解二者的區別對我們掌握整個計算機系統有很大幫助。 區別 1. 一部分庫函數實現需要使用系統調用( 如 pr…

Flask 從入門到熟悉(不敢稱為精通)

文章目錄2.1 Flask介紹及其安裝2.2 Virtualenv3.1 一個最小的應用3.2 外部課件服務器3.3 調試模式4.1 路由介紹4.2 變量規則4.3 構建URL4.4 HTTP 方法4 總結5.1 靜態文件5.2 渲染模板5.3 練習66.1 接收請求數據6.2 請求對象6.3 文件上傳6.4 Cookies6 總結77.1 重定向和錯誤7.2 …

Ext JS 5 beta版發布

原文&#xff1a;Announcing Public Beta of Ext JS 5我們非常高興的宣布&#xff0c;Sencha Ext JS 5 beta版本開始進行公測了。這個beta版本可以讓你、我們Sencha社區來對我們的Ext JS 5的工作進度進行評測。對于所以Ext JS開發人員&#xff0c;這事一個很好的機會來協助完成…

算法【二分查找】(數組)

1 .山脈數組的巔峰索引 信息 我們把符合下列屬性的數組 A 稱作山脈&#xff1a; A.length > 3 存在 0 < i < A.length - 1 使得A[0] < A[1] < … A[i-1] < A[i] > A[i1] > … > A[A.length - 1] 給定一個確定為山脈的數組&#xff0c;返回任何滿…

關于癌癥的十大謠言

最近&#xff0c;國外網站總結了西方社會中流行的十個關于癌癥的謠言&#xff0c;其中很多謠言在我們周圍也有廣泛的傳播。 謠言1&#xff1a;癌癥是人為導致的現代疾病 或許在公眾的認知里&#xff0c;癌癥在今天要比歷史上任何時期都重要。不過實際上&#xff0c;癌癥可不是一…

[python 進階] 第7章 函數裝飾器和閉包

文章目錄7.1 裝飾器基礎知識7.2 Python何時執行裝飾器7.3 使用裝飾器改進“策略”7.4 變量作用域(global)備注 -比較字節碼&#xff08;暫略&#xff09;7.5 閉包7.6 nonlocal聲明global和nonlocal的區別7.7 實現一個簡單的裝飾器7.8 標準庫中的裝飾器7.8.1 使用functools.lru_…

自制“低奢內”CSS3登入表單,包含JS驗證,請別嫌棄哦。

要求 必備知識 基本了解CSS語法,初步了解CSS3語法知識。和JS/JQuery基本語法。 開發環境 Adobe Dreamweaver CS6 演示地址 演示地址 預覽截圖(抬抬你的鼠標就可以看到演示地址哦): 制作步驟: 一, html結構 <div id"home"><form id"login" class…

class里面只能寫以下5種

轉載于:https://www.cnblogs.com/phplearnings/p/3650849.html

【排序】算法(python實現)

文章目錄python 排序算法1 插入排序1.1 直接插入排序算法思想1.2 希爾排序算法思想2. 選擇排序2.1 簡單選擇排序2.2 堆排序參考python 排序算法 1 插入排序 1.1 直接插入排序 算法思想 直接插入排序的核心思想就是&#xff1a;將數組中的所有元素依次跟前面已經排好的元素相…

OpenSSL漏洞補救辦法詳解(轉)

CVE-2014-0160漏洞背景 2014年4月7日OpenSSL發布了安全公告&#xff0c;在OpenSSL1.0.1版本中存在嚴重漏洞(CVE-2014-0160)。OpenSSL Heartbleed模塊存在一個BUG&#xff0c;問題存在于ssl/dl_both.c文件中的心跳部分&#xff0c;當攻擊者構造一個特殊的數據包&#xff0c;滿足…

SharePoint 自定義WebPart之間的連接

1、創建SharePoint解決方案&#xff0c;添加兩個WebPart分別用來發送和接收&#xff1b; 2、發送值的WebPart需要繼承自IWebPartField(當然&#xff0c;根據需要還可以選擇IWebPartField,IWebPartParameters,IWebPartRow,IWebPartTable&#xff0c;具體參見msdn)&#xff0c;原…