You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.17 11:24:34