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

Python中__new__能否修改__init__接收的foo关键字参数?

__new__能否修改__init__接收的关键字参数?

你的猜想不对,__new__完全可以修改__init__最终接收到的参数值,只是你的代码写法有问题,导致没达到预期效果。

你的代码为什么失效?

你在__new__里递归调用cls.__new__时,虽然传入了foo=float(foo),但Python的对象创建流程是这样的:当__new__返回当前类的实例时,Python会自动用构造函数调用时的原始参数去调用__init__,而不是你在__new__里修改后的参数。你的递归调用最终还是会走到return super().__new__(cls),此时返回实例后,__init__拿到的依然是最初调用Wibble(use_floats_only=True)时的参数——也就是默认的foo=42(int类型),因为你没在原始调用里传foo,所以__init__用的是默认值。

正确的实现方式

有两种可靠的方法让__new__修改__init__的参数:

方法1:手动调用__init__并传入修改后的参数

直接在__new__里创建实例后,手动调用__init__并传递修改后的参数,这样就能覆盖默认的__init__调用:

import sys
class Wibble(object):
    def __new__(cls, *args, foo=42, **kwargs):
        use_floats = kwargs.pop('use_floats_only', False)
        instance = super().__new__(cls)
        if use_floats:
            print('Warning: using floats only!', file=sys.stderr)
            # 修改foo为浮点型后,手动调用__init__
            instance.__init__(*args, foo=float(foo), **kwargs)
        else:
            # 正常调用__init__
            instance.__init__(*args, foo=foo, **kwargs)
        return instance

    def __init__(self, *args, foo=42, **kwargs):
        self.foo = foo

执行print(type(Wibble(use_floats_only=True).foo))会输出<class 'float'>,符合预期。

方法2:在实例中暂存修改后的值,让__init__读取

在__new__里把修改后的foo存在实例的临时属性中,然后在__init__里优先使用这个临时值:

import sys
class Wibble(object):
    def __new__(cls, *args, foo=42, **kwargs):
        use_floats = kwargs.pop('use_floats_only', False)
        instance = super().__new__(cls)
        if use_floats:
            print('Warning: using floats only!', file=sys.stderr)
            # 把修改后的foo存在临时属性里
            instance._temp_foo = float(foo)
        return instance

    def __init__(self, *args, foo=42, **kwargs):
        # 优先用临时属性的foo,没有则用传入的默认值
        self.foo = getattr(self, '_temp_foo', foo)
        # 清理临时属性(可选)
        if hasattr(self, '_temp_foo'):
            delattr(self, '_temp_foo')

这种方式不需要手动调用__init__,更符合Python的默认流程,同时也能达到修改参数的目的。

核心原理总结

Python构造对象的流程是:

  1. 调用类名(...)时,先触发__new__方法,传入的是构造函数的原始参数
  2. 如果__new__返回当前类的实例,Python会自动用原始参数调用该实例的__init__
  3. 若想让__init__拿到修改后的参数,要么手动调用__init__传修改后的参数,要么在__new__里把修改值存在实例上,让__init__读取。

内容的提问来源于stack exchange,提问作者kjo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 13:52:37