未知类型场景下的Python函数分派模式实现问询
基于属性的Python函数分派实现方案
方法一:主函数内手动判断属性并分发
这是最直接的实现方式,在单分派主函数里先检查传入对象的属性,匹配到目标属性后调用对应处理逻辑:
from functools import singledispatch @singledispatch def fun(value): # 优先检查是否具备目标属性,命中则调用专属处理函数 if hasattr(value, "specific_attr"): return _handle_specific_attr(value) # 默认处理逻辑 print("Default handling for other types") def _handle_specific_attr(value): print(f"Processing object with specific_attr: {value.specific_attr}")
这种方式简单直观,适合属性判断规则少的场景,但规则增多后主函数会变得冗余。
方法二:用抽象基类扩展单分派机制
通过定义抽象基类,利用__subclasshook__让所有具备目标属性的类型自动成为该基类的“虚拟子类”,从而复用singledispatch的注册机制:
from functools import singledispatch from abc import ABC, abstractmethod # 定义抽象基类,通过钩子函数判断属性 class HasSpecificAttr(ABC): @classmethod def __subclasshook__(cls, subclass): # 只要类拥有目标属性,就被视为该基类的子类 return hasattr(subclass, "specific_attr") @singledispatch def fun(value): print("Default handling for other types") # 注册针对HasSpecificAttr的处理逻辑 @fun.register(HasSpecificAttr) def _(value): print(f"Processing object with specific_attr: {value.specific_attr}")
测试示例:
# 测试类1:拥有目标属性 class TestA: def __init__(self): self.specific_attr = "Test A's attribute" # 测试类2:无目标属性 class TestB: pass fun(TestA()) # 输出: Processing object with specific_attr: Test A's attribute fun(TestB()) # 输出: Default handling for other types
这种方式贴合singledispatch的设计风格,方便扩展多种属性判断场景。
方法三:自定义属性分派装饰器
如果需要支持多属性组合判断,可以自己实现一个完全基于属性的分派装饰器:
def attr_dispatch(func): registry = [] def register(*attrs): def decorator(handler): registry.append((attrs, handler)) return handler return decorator def wrapper(value): # 遍历所有注册的属性规则,匹配到第一个符合条件的就执行对应逻辑 for attrs, handler in registry: if all(hasattr(value, attr) for attr in attrs): return handler(value) # 无匹配时执行原函数的默认逻辑 return func(value) wrapper.register = register return wrapper # 使用自定义装饰器 @attr_dispatch def fun(value): print("Default handling for other types") # 注册仅拥有specific_attr的处理逻辑 @fun.register("specific_attr") def _(value): print(f"Processing object with specific_attr: {value.specific_attr}") # 注册同时拥有attr1和attr2的处理逻辑 @fun.register("attr1", "attr2") def _(value): print(f"Processing object with attr1: {value.attr1} and attr2: {value.attr2}")
这种方式灵活性最高,完全脱离类型限制,只关注对象的属性特征。
内容的提问来源于stack exchange,提问作者Johnny Daou
相关产品推荐
相关产品推荐

