Python中通過(guò)@classmethod 實(shí)現(xiàn)多態(tài)的示例
通過(guò)@classmethod 實(shí)現(xiàn)多態(tài)
1.概述
python中通常使用對(duì)象創(chuàng)建多態(tài)模式,python還支持類創(chuàng)建多態(tài)模式。下面通過(guò)一個(gè)例子展示它如何實(shí)現(xiàn)多態(tài)。
通過(guò)對(duì)象創(chuàng)建多態(tài)和類創(chuàng)建多態(tài)開(kāi)發(fā)模式區(qū)別
- 對(duì)象多態(tài)模式:接收的是一個(gè)父類類型對(duì)象,然后通過(guò)傳入父類的子類對(duì)象調(diào)用普通同名方法,實(shí)現(xiàn)不同的行為。
- 類多態(tài)模式:接收的一個(gè)父類,然后通過(guò)傳入父類的子類調(diào)用同名的類方法,實(shí)現(xiàn)不通的行為
2.類方法創(chuàng)建多態(tài)模式示例
2.1.普通模式
先通過(guò)一個(gè)的示例看下常規(guī)方式發(fā)開(kāi)的代碼沒(méi)有使用多態(tài)時(shí)候存在的問(wèn)題,然后在通過(guò)類多態(tài)來(lái)優(yōu)化代碼。
下面實(shí)現(xiàn)一個(gè)讀取數(shù)據(jù),然后處理數(shù)據(jù)的示例,他有兩條繼承體系。
輸入信息體系:將輸入信息的方式創(chuàng)建為類繼承關(guān)系,可以根據(jù)讀取信息的方式創(chuàng)建不同的InputData子類。
處理數(shù)據(jù)體系:將處理信息的方式創(chuàng)建類繼承關(guān)系,根據(jù)對(duì)信息處理的方式創(chuàng)建不同的Worker子類。
然后通過(guò)mapreduce函數(shù)組合業(yè)務(wù)執(zhí)行邏輯,最后輸出運(yùn)行結(jié)果。
# 接收輸入信息類體系
class InputData:
def read(self):
raise NotImplementedError
class PathInputData(InputData):
def __init__(self,path):
super().__init__()
self.path = path
def read(self):
with open(self.path) as f:
return f.read()
# 處理信息類體系
class Worker:
def __init__(self, input_data):
self.input_data = input_data
self.result = None
def map(self):
raise NotImplementedError
def reduce(self, other):
raise NotImplementedError
class LineCountWorker(Worker):
def map(self):
data = self.input_data
self.result = data.count('/n')
def reduce(self, other):
self.result += other.result
# 組合業(yè)務(wù)
import os
def generate_inputs(data_dit):
for name in os.listdir(data_dit):
# 讀文件內(nèi)容
yield PathInputData(os.path.join(data_dit, name))
def create_workers(input_list):
workers = []
for input_data in input_list:
# 處理數(shù)據(jù)
workers.append(LineCountWorker(input_data))
return workers
from threading import Thread
def execute(workers):
threads = [Thread(target=w.map) for w in workers]
for thread in threads: thread.start()
for thread in threads: thread.join()
first, *rest = workers
for worker in rest:
first.reduce(worker)
return first.result
def mapreduce(data_dir):
inputs = generate_inputs(data_dir)
workers = create_workers(inputs)
return execute(workers)
import os
import random
def write_test_files(tmpdir):
os.makedirs(tmpdir)
for i in range(100):
with open(os.path.join(tmpdir, str(i)), 'w') as f:
f.write('\n' * random.randint(0, 100))
tmpdir = 'test_inputs'
write_test_files(tmpdir)
result = mapreduce(tmpdir)
print(f'There are {result} lines')
上面接收信息處理信息的示例存在兩個(gè)問(wèn)題:
- mapreduce函數(shù)通用性不好,不易擴(kuò)展。例如現(xiàn)在創(chuàng)建了新的InputData、Worker子類,那么就要?jiǎng)?chuàng)建一個(gè)新的mapreduce函數(shù)來(lái)組合新的業(yè)務(wù)流程,這樣會(huì)導(dǎo)致重復(fù)的代碼越來(lái)越多,不利于維護(hù)。
- python不能向java語(yǔ)言可以在一個(gè)類中以重載的形式創(chuàng)建多個(gè)構(gòu)造器,創(chuàng)建一個(gè)構(gòu)造器多態(tài)讓子類可以根據(jù)不同的構(gòu)造器接收不同的參數(shù)。而python不能這么做,因?yàn)閜ython的類只能有一個(gè)構(gòu)造方法(init),所以沒(méi)有辦法為不同的子類提供多種形式的形參構(gòu)造器,在繼承中也沒(méi)有辦法要求所有的子類都只接收只有一種方式參數(shù)的構(gòu)造方法。因?yàn)樽宇愐鶕?jù)自身的特點(diǎn)接收不同類型的參數(shù)。
這個(gè)問(wèn)題最好能夠通過(guò)類方法多態(tài)來(lái)解決,這種多態(tài)與實(shí)例方法多態(tài)很像,只不過(guò)他針對(duì)的是類,而不是這些類的對(duì)象。
2.2.類方法多態(tài)重構(gòu)業(yè)務(wù)
類方法多態(tài)的實(shí)現(xiàn)非常簡(jiǎn)單,下面將代碼中關(guān)鍵的點(diǎn)提煉出來(lái)。
- 在父類中創(chuàng)建一個(gè)通用的方法,不需要實(shí)現(xiàn)任何業(yè)務(wù)邏輯,然后讓子類中重寫(xiě)該方法,實(shí)現(xiàn)不同的行為。在方法上使用@classmethod裝飾器聲明為類方法,方便調(diào)用時(shí)候可以以類調(diào)用,而不是實(shí)例對(duì)象調(diào)用,通過(guò)子類重寫(xiě)父類的類方法就是類方法多態(tài)。
- 在GenericInputData類中定義一個(gè)類方法(generate_inputs)用來(lái)解決python只有一個(gè)構(gòu)造方法不能實(shí)現(xiàn)多種方式接收參數(shù)的弊端,子類通過(guò)重寫(xiě)該方法,實(shí)現(xiàn)接收多種參數(shù)行為。
class GenericInputData:
def read(self):
raise NotImplementedError
# 創(chuàng)建一個(gè)多態(tài)的類方法,讓子類實(shí)現(xiàn)不同的功能
@classmethod
def generate_inputs(cls, config):
raise NotImplementedError
class PathInputData(GenericInputData):
def __init__(self, path):
super().__init__()
self.path = path
def read(self):
with open(self.path) as f:
return f.read()
# 子類重寫(xiě)父類的類方法
@classmethod
def generate_inputs(cls, config):
data_dir = config['data_dir']
for name in os.listdir(data_dir):
yield cls(os.path.join(data_dir, name))
class GenericWorker:
def __init__(self, input_data):
self.input_data = input_data
self.result = None
def map(self):
raise NotImplementedError
def reduce(self, other):
raise NotImplementedError
@classmethod
def create_workers(cls, input_class, config):
workers = []
for input_data in input_class.generate_inputs(config):
workers.append(cls(input_data))
return workers
class LineCountWorker(GenericWorker):
def map(self):
data = self.input_data.read()
self.result = data.count('\n')
def reduce(self, other):
self.result += other.result
# 定義的形參類型為父類,實(shí)現(xiàn)了類方法多態(tài)
def mapreduce(worker_class, input_class, config):
workers = worker_class.create_workers(input_class, config)
return execute(workers)
config = {'data_dir': tmpdir}
result = mapreduce(LineCountWorker, PathInputData, config)
print(f'There are {result} lines')通過(guò)類方法多態(tài)重構(gòu)代碼后,mapreduce函數(shù)支持了多態(tài),它接收的是一個(gè)父類類型,根據(jù)傳入的實(shí)際子類實(shí)現(xiàn)把不同的功能。當(dāng)再擴(kuò)展GenericInputData、GenericWorker子類后,mapreduce函數(shù)不需要修改代碼,實(shí)現(xiàn)了左開(kāi)右閉原則。
到此這篇關(guān)于Python中通過(guò)@classmethod 實(shí)現(xiàn)多態(tài)的文章就介紹到這了,更多相關(guān)@classmethod 實(shí)現(xiàn)多態(tài)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Python標(biāo)準(zhǔn)庫(kù)中內(nèi)置裝飾器@staticmethod和@classmethod
- python中的class_static的@classmethod的巧妙用法
- 詳解Python中@staticmethod和@classmethod區(qū)別及使用示例代碼
- Python 類方法和實(shí)例方法(@classmethod),靜態(tài)方法(@staticmethod)原理與用法分析
- python @classmethod 的使用場(chǎng)合詳解
- 對(duì)Python中的@classmethod用法詳解
- Python類方法@classmethod()的具體使用
相關(guān)文章
Python實(shí)現(xiàn)的尋找前5個(gè)默尼森數(shù)算法示例
這篇文章主要介紹了Python實(shí)現(xiàn)的尋找前5個(gè)默尼森數(shù)算法,簡(jiǎn)單講述了默尼森數(shù)的概念,并結(jié)合實(shí)例形式分析了Python求解默尼森數(shù)算法的相關(guān)操作技巧,需要的朋友可以參考下2018-03-03
python實(shí)現(xiàn)Zabbix-API監(jiān)控
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)Zabbix-API監(jiān)控,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-09-09
Python程序設(shè)計(jì)入門(mén)(2)變量類型簡(jiǎn)介
這篇文章主要介紹了Python變量類型,需要的朋友可以參考下2014-06-06
Python+OpenCV實(shí)現(xiàn)黑白老照片上色功能
我們都知道,有很多經(jīng)典的老照片,受限于那個(gè)時(shí)代的技術(shù),只能以黑白的形式傳世。盡管黑白照片別有一番風(fēng)味,但是彩色照片有時(shí)候能給人更強(qiáng)的代入感。本文就來(lái)用Python和OpenCV實(shí)現(xiàn)老照片上色功能,需要的可以參考一下2023-02-02
關(guān)于Pytorch的MLP模塊實(shí)現(xiàn)方式
今天小編就為大家分享一篇關(guān)于Pytorch的MLP模塊實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-01-01
TensorFlow深度學(xué)習(xí)之卷積神經(jīng)網(wǎng)絡(luò)CNN
這篇文章主要介紹了TensorFlow深度學(xué)習(xí)之卷積神經(jīng)網(wǎng)絡(luò)CNN2018-03-03
使用python修改文件并立即寫(xiě)回到原始位置操作(inplace讀寫(xiě))
這篇文章主要介紹了使用python修改文件并立即寫(xiě)回到原始位置操作(inplace讀寫(xiě)),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-06-06

