【问题标题】:Any ideas about the best work around for __new__ losing its arguments?关于 __new__ 失去其论点的最佳解决方法的任何想法?
【发布时间】:2026-01-23 03:30:02
【问题描述】:

所以,我今天才意识到 __new__ 已被弃用以接收参数,从 python 2.6 开始(文档中没有提到它,这在 __new__ 调用 @987654324 的行为方面也是不正确的@据我所知)。这意味着我的功能代码已经开始发出警告,我想摆脱它们。但我看不到一种优雅的解决方法。

我有一堆在构造时执行优化的类。所以我有

class Conjunction(Base):
    def __new__(cls, a, b):
       if a == True: 
          return b
       elif b == True
          return a
       else:
          return super(Conjunction,cls).__new__(cls, a, b)

等等(真实版本涵盖更多案例)。因此,与 Guido 在 this response(我能找到的唯一引用)中所说的不同,我的 __new__ 方法确实使用了它的参数,并且不能被替换为覆盖__init__ 函数。

我能做的最好的就是把它一分为二:

def Conjunction(a, b):
   if a == True: 
      return b
   elif b == True
      return a
   else:
      return ConjunctionImpl(a, b)

class ConjunctionImpl(Base):
   # ...

但这实在是太丑了,臭到天上。我是否缺少一种优雅的方式让类构造函数根据给定的构造函数参数返回一些任意对象?

【问题讨论】:

  • 这不是构造函数的本意。如果你想要这种行为,请使用一个函数(就像你在第二个例子中所做的那样)。
  • 你能说更多吗?这与单例示例有何不同,单例示例始终被用作说明为什么首先需要 __new__ 的典型示例?

标签: python


【解决方案1】:

__new__ 不是“因接收参数而弃用”。 Python 2.6 中的变化是 object.__new__object 类的 __new__ 方法,不再忽略它传递的任何参数。 (object.__init__ 也不再忽略参数,但这只是 2.6 中的警告。)如果要将参数传递给 __new__ 或 @987654327,则不能使用 object 作为继承的终止类@。

为了让任何代码在 2.6 中依赖该行为,您只需将 object 替换为基类,使用正确接受额外参数并且 传递的基类它们在它发出的调用中一起使用(使用super()。)

【讨论】:

  • 你知道,这就是我喜欢 * 的原因:当 PSF 的董事会成员过来回答问题时。谢谢托马斯!我从警告消息中得到了错误的结果。我应该补充一点,我的跟踪中的解决方案是微不足道的:向我的基类添加一个 __new__ 方法,其中包含以下行: def __new__(cls, *args, **kws): instance = super(Base, cls).__new__( cls) instance.__init__(*args, **kws) 返回实例
  • 不过,今晚你是我的英雄。
【解决方案2】:

Thomas 在他的回答中给了我正确的答案,但我应该补充一点,在我的情况下,解决方案是微不足道的:在我的基类中添加一个 __new__ 方法,其中包含以下行:

class Base(object):
    def __new__(cls, *args, **kws):
        instance = super(Base, cls).__new__(cls)
        instance.__init__(*args, **kws)
        return instance

【讨论】:

    【解决方案3】:

    这让我很好奇,因为我没有在文档中看到弃用,所以我自己尝试了一下。

    class Foo(object):
        def __new__(cls, a, b):
            if a:
                return a
            elif b:
                return b
            else:
                return super(Foo, cls).__new__(cls, a, b)
    
        def __init__(self, a, b):
            self.a = a
            self.b = b
    
    class Bar(Foo):
        def __new__(cls, x, y):
            if x:
                return x
            if y:
                return y
            else:
                return super(Bar, cls).__new__(cls, x, y)
    
    
    foo = Bar(False, False)
    

    正如您在此示例中所看到的,我覆盖了 Foo 中的 init,因为任何传递给 new 的 args 都将被转发到 __new__ 尝试创建的 cls 实例。 foo 的实例属于 Bar 类,但它有成员 a 和 b。我通过不覆盖它来调用超类的__init__。方法__new__ 总是将其参数传递给__init__。如果您不覆盖对象的__init__,它将失败,因为该方法不接受任何参数。

    这是我对 Python 2.7 中 new 用法的看法。根据文档 2.6 类似。

    【讨论】:

    • 谢谢。我不认为这是正在发生的事情。我不认为这是 __init__ 失败。
    最近更新 更多