日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

python[进阶] 6.使用一等函数实现设计模式

發(fā)布時間:2023/12/10 python 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python[进阶] 6.使用一等函数实现设计模式 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

    • 6.1.1 經(jīng)典的“策略”模式
    • 6.1.2 使用函數(shù)實現(xiàn)“策略”模式
    • 6.1.3 選擇最佳策略:簡單的
    • 6.1.4 找出模塊中的全部
  • 6.2 “命令”模式

6.1.1 經(jīng)典的“策略”模式

為抽象基類(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):#第三個具體策略"""訂單中的不同商品達(dá)到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>

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

6.1.2 使用函數(shù)實現(xiàn)“策略”模式

這個例子是對上面的例子 的重構(gòu),把具體策略換成了簡單的函數(shù),而且去掉了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):"""訂單中的不同商品達(dá)到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>

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

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

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):"""訂單中的不同商品達(dá)到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 中,模塊也是一等對象,而且標(biāo)準(zhǔn)庫提供了幾個處理模塊的函數(shù)。Python 文檔
是這樣說明內(nèi)置函數(shù) globals 的。

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

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 函數(shù)幫助 best_promo 自動找到其他可用的 *_promo 函數(shù),過程
有點曲折。

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)

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

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

6.2 “命令”模式

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

總結(jié)

以上是生活随笔為你收集整理的python[进阶] 6.使用一等函数实现设计模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。