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

为何猴子补丁修改类的`__new__`方法并非总能生效?

为何猴子补丁修改类的__new__方法并非总能生效?

这个问题其实戳中了Python方法绑定机制的一个小细节,我来给你一步步掰明白~

先回顾下你遇到的两种矛盾场景:

  • 直接把A.__new__设为object.__new__,实例化完全正常;
  • 先把A.__new__替换成自定义的mynew,再改回object.__new__,就会抛出TypeError,说object.__new__()只接受一个参数。

核心原因:方法绑定的差异

Python里的方法不是孤立的函数——当你把一个函数赋值给类的属性时,Python会根据上下文自动处理绑定逻辑:

  1. 直接赋值object.__new__的情况:
    当你直接执行A.__new__ = object.__new__时,Python会识别出这是要把父类的__new__方法继承给子类,此时object.__new__会被绑定为A类的类方法。调用A(10)时,Python会自动把A作为第一个参数cls传给object.__new__,剩下的参数会被忽略(因为object.__new__本来就只需要cls),所以实例化正常。

  2. 先替换自定义函数再改回的情况:
    当你先把A.__new__设为普通函数mynew后,类的__new__属性就变成了一个未绑定的普通函数。此时再执行A.__new__ = object.__new__,你其实是把object类里的未绑定函数直接赋值给了A.__new__——这个函数不会自动绑定到A类上,调用A(10)时,Python会把A和10两个参数一起传给它,而object.__new__只接受cls一个参数,自然就报错了。

怎么正确重置__new__方法?

有两个靠谱的解决方案:

方案1:提前保存原始的__new__

在进行猴子补丁之前,先把类原本的__new__方法存起来,重置的时候直接用保存的版本:

class A:
    def __init__(self, x):
        self.x = x

# 提前备份原始方法
original_new = A.__new__

def mynew(cls, *args, **kwargs):
    print("Calling mynew")
    return object.__new__(cls)

# 打补丁
A.__new__ = mynew
A(10)  # 正常输出:Calling mynew

# 重置回原始版本
A.__new__ = original_new
A(10)  # 正常实例化,无报错

方案2:用包装函数适配参数

如果没提前备份,也可以用一个lambda或者包装函数,把object.__new__包装成能接受任意参数的形式,只把cls传给它:

# 错误重置方式:直接赋值object.__new__
# A.__new__ = object.__new__

# 正确重置方式:用包装函数适配参数
A.__new__ = lambda cls, *args, **kwargs: object.__new__(cls)
A(10)  # 正常工作

这样就能避开方法绑定的坑,顺利完成重置啦~

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 12:24:36