通过@classmethod 实现多态
创始人
2024-02-16 20:03:30
0

通过@classmethod 实现多态

1.概述

python中通常使用对象创建多态模式,python还支持类创建多态模式。下面通过一个例子展示它如何实现多态。

通过对象创建多态和类创建多态开发模式区别

  • 对象多态模式:接收的是一个父类类型对象,然后通过传入父类的子类对象调用普通同名方法,实现不同的行为。
  • 类多态模式:接收的一个父类,然后通过传入父类的子类调用同名的类方法,实现不通的行为

2.类方法创建多态模式示例

2.1.普通模式

先通过一个的示例看下常规方式发开的代码没有使用多态时候存在的问题,然后在通过类多态来优化代码。

下面实现一个读取数据,然后处理数据的示例,他有两条继承体系。
输入信息体系:将输入信息的方式创建为类继承关系,可以根据读取信息的方式创建不同的InputData子类。
处理数据体系:将处理信息的方式创建类继承关系,根据对信息处理的方式创建不同的Worker子类。

然后通过mapreduce函数组合业务执行逻辑,最后输出运行结果。

# 接收输入信息类体系
class InputData:def read(self):raise NotImplementedErrorclass PathInputData(InputData):def __init__(self,path):super().__init__()self.path = pathdef read(self):with open(self.path) as f:return f.read()# 处理信息类体系
class Worker:def __init__(self, input_data):self.input_data = input_dataself.result = Nonedef map(self):raise NotImplementedErrordef reduce(self, other):raise NotImplementedErrorclass LineCountWorker(Worker):def map(self):data = self.input_dataself.result = data.count('/n')def reduce(self, other):self.result += other.result# 组合业务
import os
def generate_inputs(data_dit):for name in os.listdir(data_dit):# 读文件内容yield PathInputData(os.path.join(data_dit, name))def create_workers(input_list):workers = []for input_data in input_list:# 处理数据workers.append(LineCountWorker(input_data))return workersfrom 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 = workersfor worker in rest:first.reduce(worker)return first.resultdef 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')

上面接收信息处理信息的示例存在两个问题:

  • mapreduce函数通用性不好,不易扩展。例如现在创建了新的InputData、Worker子类,那么就要创建一个新的mapreduce函数来组合新的业务流程,这样会导致重复的代码越来越多,不利于维护。
  • python不能向java语言可以在一个类中以重载的形式创建多个构造器,创建一个构造器多态让子类可以根据不同的构造器接收不同的参数。而python不能这么做,因为python的类只能有一个构造方法(init),所以没有办法为不同的子类提供多种形式的形参构造器,在继承中也没有办法要求所有的子类都只接收只有一种方式参数的构造方法。因为子类要根据自身的特点接收不同类型的参数。

这个问题最好能够通过类方法多态来解决,这种多态与实例方法多态很像,只不过他针对的是,而不是这些类的对象

2.2.类方法多态重构业务

类方法多态的实现非常简单,下面将代码中关键的点提炼出来。

  • 在父类中创建一个通用的方法,不需要实现任何业务逻辑,然后让子类中重写该方法,实现不同的行为。在方法上使用@classmethod装饰器声明为类方法,方便调用时候可以以类调用,而不是实例对象调用,通过子类重写父类的类方法就是类方法多态。
  • 在GenericInputData类中定义一个类方法(generate_inputs)用来解决python只有一个构造方法不能实现多种方式接收参数的弊端,子类通过重写该方法,实现接收多种参数行为。
class GenericInputData:def read(self):raise NotImplementedError# 创建一个多态的类方法,让子类实现不同的功能@classmethoddef generate_inputs(cls, config):raise NotImplementedErrorclass PathInputData(GenericInputData):def __init__(self, path):super().__init__()self.path = pathdef read(self):with open(self.path) as f:return f.read()# 子类重写父类的类方法@classmethoddef 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_dataself.result = Nonedef map(self):raise NotImplementedErrordef reduce(self, other):raise NotImplementedError@classmethoddef create_workers(cls, input_class, config):workers = []for input_data in input_class.generate_inputs(config):workers.append(cls(input_data))return workersclass LineCountWorker(GenericWorker):def map(self):data = self.input_data.read()self.result = data.count('\n')def reduce(self, other):self.result += other.result# 定义的形参类型为父类,实现了类方法多态
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')

通过类方法多态重构代码后,mapreduce函数支持了多态,它接收的是一个父类类型,根据传入的实际子类实现把不同的功能。当再扩展GenericInputData、GenericWorker子类后,mapreduce函数不需要修改代码,实现了左开右闭原则。

相关内容

热门资讯

原创 私... 西安雁塔警方通报查处一家提供“异性陪侍”的私人影院,经营者被刑拘,陪侍人员被行拘。这背后,为何处理结...
天玑科技及相关责任人因涉嫌串通... 12月22日,天玑科技(300245.SZ)发布公告,公司近期收到上海市虹口区人民检察院送达的《起诉...
「期刊文摘」 蔡昉:人工智能时... 蔡昉:人工智能时代的社会保障,理念更新与制度建设 期刊文摘 ★★★★★ 一、引言 人们惊叹于近年来人...
千万人受益 详解信用修复政策 个人信用修复政策重磅落地。12月22日,中国人民银行发布一次性信用修复政策:符合相关条件的逾期信息,...
“祥源系”爆雷后,“浙商大佬”... 22日晚间,交建股份、祥源文旅双双发布公告称,公司于2025年12月22日收到公司实际控制人俞发祥家...
涉嫌串通投标!天玑科技及相关责... 天玑科技12月22日晚间公告,公司于近日收到上海市虹口区人民检察院送达的《起诉书》,上海市虹口区人民...
深圳龙华举行法律援助志愿律师首... 为进一步提升法律援助服务质量,加强法律援助志愿律师队伍建设,12月17日下午,龙华区司法局组织开展了...
(图表)十年来全国检察机关共办... 新华社图表,北京,2025年12月22日 记者从最高人民法院、最高人民检察院12月22日举行的发布...
反思独居蒋女士离世事件:补齐制... 家住上海虹口区的46岁独居人士蒋女士,12月14日因病离世,但她的遗产不能用来购买墓地,引发舆论广泛...
俄副外长:保证不进攻欧盟北约,... 【文/观察者网 柳白】 据俄新社报道,当地时间12月22日,俄罗斯外交部副部长谢尔盖·里亚布科夫在...