Python如何正确为singledispatchmethod叠加自定义装饰器
singledispatchmethod叠加自定义装饰器实现方案
错误写法根源
singledispatchmethod是实现了__get__的描述符对象,它的register属性绑定在描述符实例上,实际调用时会根据参数类型直接查内部的registry分发表找对应实现,不会走你在基础方法上包的装饰层,装饰器叠放位置不对就会出现属性丢失、装饰逻辑不触发、参数识别错误的问题。
方案1:全局装饰所有分派逻辑
如果需要让所有注册的类型处理方法都应用同一个装饰器,不需要逐个修改方法定义,等所有分派方法注册完成后,遍历分发表统一包装即可:
from functools import singledispatchmethod, wraps def eavesdrop(method): @wraps(method) def wrapper(self, arg): print(f"Negating {arg}") return method(self, arg) return wrapper class Negator: @singledispatchmethod def neg(self, arg): raise NotImplementedError("Cannot negate a") @neg.register def _(self, arg: int): return -arg @neg.register def _(self, arg: bool): return not arg @neg.register def _(self, arg: float): return -arg # 批量给所有已注册的非默认实现应用装饰器 for data_type, handler in Negator.neg.registry.items(): if data_type is not object: # 跳过默认的未注册类型兜底方法,按需调整 Negator.neg.register(data_type, eavesdrop(handler))
测试调用时,所有已注册类型的处理逻辑都会先触发打印逻辑,再执行原计算,未注册类型仍正常抛出未实现错误。
方案2:单独给指定分派方法加装饰器
如果只需要给部分类型的处理逻辑加装饰器,使用带参数的register(类型)写法即可,不要用无参数的register叠放装饰器:
from functools import singledispatchmethod, wraps def eavesdrop(method): @wraps(method) def wrapper(self, arg): print(f"Negating {arg}") return method(self, arg) return wrapper class Negator: @singledispatchmethod def neg(self, arg): raise NotImplementedError("Cannot negate a") # int类型加装饰器:先指定注册类型,再应用自定义装饰器 @neg.register(int) @eavesdrop def _(self, arg: int): return -arg # bool类型不加装饰器,正常注册即可 @neg.register def _(self, arg: bool): return not arg # float类型加装饰器 @neg.register(float) @eavesdrop def _(self, arg: float): return -arg
无参数版@neg.register依赖函数本身的类型注解识别注册类型,中间插入装饰器后,register拿到的是装饰器返回的包装函数,丢失了原函数的类型注解,就会抛出参数无效的错误。换成带参数的register写法,会先接收明确的类型参数,返回的装饰器再去包装已经处理好的目标函数,就不会出现识别问题。
原有错误写法的问题说明
@eavesdrop放在@singledispatchmethod外层:装饰器返回的是普通函数,不存在register属性,后续注册分派方法时直接触发AttributeError@eavesdrop放在@singledispatchmethod内层、基础方法上方:装饰的是默认兜底方法,单分派调用时会直接命中对应类型的注册实现,根本不会走到这个兜底方法的包装层,装饰逻辑完全不生效@eavesdrop插在@neg.register和方法定义之间:无参数register无法从包装函数上读取类型注解,触发TypeError
内容的提问来源于stack exchange,提问作者Lora
相关产品推荐
相关产品推荐

