使用singledispatchmethod重载__new__方法无法按类型区分,始终调用初始方法的原因
singledispatchmethod重载__new__方法无法按类型区分,始终调用初始方法的原因
这个问题我之前也碰到过,当时折腾了好一会儿才搞明白核心原因——__new__特殊方法的调用逻辑和singledispatchmethod的工作机制不兼容。
具体原因拆解:
__new__是Python对象创建流程中的核心特殊方法,它的调用路径和普通方法完全不同。当你执行Foo(...)时,Python默认元类type的__call__方法会直接从类的方法解析顺序(MRO)中获取__new__的原始函数对象,然后直接调用它,完全绕过了普通方法的descriptor属性访问流程。- 而
singledispatchmethod的类型分发逻辑,是依赖它作为descriptor的__get__方法实现的:当你访问被它装饰的方法时,__get__会生成一个带类型判断的包装函数,再执行分发逻辑。但因为__new__的调用跳过了这个descriptor流程,所以它的重载分支根本没机会被触发,自然每次都只会执行初始的默认方法。
可行的解决方案
既然直接给__new__加singledispatchmethod行不通,我们可以换个思路:把类型分发逻辑放到一个单独的类方法里,让__new__委托调用这个方法即可:
from functools import singledispatchmethod class Foo: def __new__(cls, arg1, **kwargs): # 将实际逻辑委托给带分发逻辑的类方法 return cls._new_impl(arg1, **kwargs) @singledispatchmethod @classmethod def _new_impl(cls, arg1, **kwargs): return "default call" @_new_impl.register(int) @classmethod def _(cls, arg1, **kwargs): return "called with int " + str(arg1) print(Foo("hi")) # 输出: default call print(Foo(1)) # 输出: called with int 1
这样修改后,_new_impl作为普通类方法,会正常触发singledispatchmethod的类型分发逻辑,间接实现了__new__按参数类型重载的需求。
备注:内容来源于stack exchange,提问作者Daraan
相关产品推荐
相关产品推荐

