如何在Python中实现可适配多种输入类型的适配器函数?
高效实现多输入格式适配函数的方案
问题背景
我有多个解决同一问题的函数(各自基于不同算法、具备不同特性),由不同开发者编写,每个函数接受的输入格式各不相同。举个简化案例:所有函数处理的都是一组物品,但:
- 函数A接受dict类型输入:键为物品名称,值为对应物品的数量
- 函数B接受list类型输入:每个元素是物品名称,且每种物品仅出现一次
需求是构建一个通用适配器函数,让用户可以用任意输入格式(dict或list)调用任意函数(A或B)。
最初的伪代码实现如下,但存在明显缺陷:当有n种输入格式时,需要编写n²个判断分支,扩展性极差:
def adapter(func:callable, input:any): if (input is a dict and func expects a dict): return func(input) elif (input is a list and func expects a list): return func(input) elif (input is a list and func expects a dict): return func({key:1 for key in list}) # convert list to dict elif (input is a dict and func expects a list): return func(list(input.keys())) # convert dict to list else: raise TypeError
高效解决方案:用格式转换注册表替代硬编码判断
核心思路是拆分适配逻辑,将“标记函数期望格式”和“格式转换规则”分离,避免大量if-else分支。
1. 给函数标记期望的输入格式
用装饰器为每个函数添加元数据,明确其期望的输入类型:
def expects_input_type(input_type): def decorator(func): func.expected_input = input_type return func return decorator # 标记函数A期望dict类型输入 @expects_input_type(dict) def funcA(items_dict): return sum(items_dict.values()) # 示例逻辑:计算总物品数量 # 标记函数B期望list类型输入 @expects_input_type(list) def funcB(items_list): return len(items_list) # 示例逻辑:统计物品种类数
2. 维护格式转换注册表
创建一个字典存储格式转换规则,键为(源格式类型, 目标格式类型)的元组,值为对应的转换函数:
# 格式转换注册表:(源类型, 目标类型) → 转换函数 converters = { (list, dict): lambda lst: {item: 1 for item in lst}, # list转dict,默认数量为1 (dict, list): lambda dct: list(dct.keys()), # dict转list,取所有物品名称 (dict, dict): lambda x: x, # 格式一致时直接返回 (list, list): lambda x: x }
3. 实现通用适配器函数
核心逻辑简化为:获取函数期望格式→查找转换规则→转换输入→调用函数:
def adapter(func, input_data): input_type = type(input_data) target_type = getattr(func, 'expected_input', None) if not target_type: raise TypeError("函数未标记期望的输入格式") # 查找对应的转换函数 convert_func = converters.get((input_type, target_type)) if not convert_func: raise TypeError(f"不支持从{input_type.__name__}转换到{target_type.__name__}") # 转换输入并调用原函数 converted_input = convert_func(input_data) return func(converted_input)
实际使用示例
# 用dict调用期望list的funcB print(adapter(funcB, {"apple": 2, "banana": 3})) # 输出:2 # 用list调用期望dict的funcA print(adapter(funcA, ["apple", "banana"])) # 输出:2
扩展优势
- 新增输入格式时,仅需两步:
- 给新函数用
expects_input_type标记目标格式 - 在
converters中添加对应的转换规则(例如新增set格式,只需补充(set, dict)、(dict, set)等转换函数)
- 给新函数用
- 无需修改适配器核心代码,完全符合开闭原则,扩展性极强
内容的提问来源于stack exchange,提问作者Erel Segal-Halevi
相关产品推荐
相关产品推荐

