__new__ 方法给出错误 object.__new__() 只接受一个参数(要实例化的类型)

新手上路,请多包涵

为什么以下代码出错?

 class Foo:
    def __new__(cls, *args, **kwargs):
        print("Creating Instance")
        instance = super(Foo, cls).__new__(cls,*args, **kwargs)
        return instance

    def __init__(self, a, b):
        self.a = a
        self.b = b

z= Foo(2,3)

它给出了以下错误

TypeError: object.__new__() takes exactly one argument (the type to instantiate)

原文由 Danish Mahmood 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 3k
2 个回答
    instance = super(Foo, cls).__new__(cls,*args, **kwargs)

是正确的。但是, 有责任首先删除您的课程引入的参数,以便最终调用 object.__new__ 时, *args**kwargs 都是空的。

你的代码应该是这样的

class Foo:
    def __new__(cls, a, b, *args, **kwargs):
        print("Creating Instance")
        instance = super(Foo, cls).__new__(cls, *args, **kwargs)
        return instance

    def __init__(self, a, b, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.a = a
            self.b = b

此定义从 --- 中删除了您的新参数 ab args 然后将其传递给 MRO 上的下一个人。同样适用于 __init__

原文由 chepner 发布,翻译遵循 CC BY-SA 4.0 许可协议

object.__new__() 签名是 (*args, **kwargs) ,你可以使用 inspect.signature 函数来检查。

但是为什么会出现这个错误呢? TLDR :因为您定义了自定义 __new__ 方法。

小研究

所有测试均在 Python 3.9.1 上完成。


考虑下一节课。

 class MyClass:
    def __init__(self): pass

让我们调用 object.__new__()

 >>> object.__new__(MyClass, *range(10), **{f'a{i}': i for i in range(10)})
<__main__.MyClass object at 0x000001E7B15B3550>

完全没有问题。这个类只有自定义 __init__ 而没有自定义 __new__ 。现在尝试为您的 Foo 做同样的调用:

 >>> object.__new__(Foo, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: object.__new__() takes exactly one argument (the type to instantiate)

关于 object.__new__() 的异常。此类具有自定义 __init____new__ 。当仅定义自定义 __new__ 时,您将看到相同的错误:

 >>> class OnlyNew:
...     def __new__(cls, *args, **kwargs): return super().__new__(cls)
>>> object.__new__(OnlyNew, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: object.__new__() takes exactly one argument (the type to instantiate)

让我们检查一个没有自定义 __init____new__ 的类。

 >>> class A: pass
>>> object.__new__(A, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: A() takes no arguments

完全不同的错误。


让我们检查一下它是如何与继承一起工作的。从 A 派生并定义 __init__

 >>> class B(A):
...     def __init__(self): pass
>>> object.__new__(B, *range(10), **{f'a{i}': i for i in range(10)})
<__main__.B object at 0x000001E7B15D23A0>

从 MyClass 派生并且不定义任何内容。

 >>> class MC(MyClass): pass
>>> object.__new__(MC, *range(10), **{f'a{i}': i for i in range(10)})
<__main__.MC object at 0x000001E7B15D2CA0>

从 MyClass 派生并定义 __new__

 >>> class Sub(MyClass):
    def __new__(cls, *args, **kwargs): return super().__new__(cls)
>>> object.__new__(Sub, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: object.__new__() takes exactly one argument (the type to instantiate)

从 Foo 派生并且不定义任何内容。

 >>> class F(Foo): pass
>>> object.__new__(F, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: object.__new__() takes exactly one argument (the type to instantiate)

现在让我们来看一个绝对奇特的案例:

 class Base:
    def __init__(self): pass
    def __new__(cls, *args, **kwargs): return super().__new__(cls)

class Sub(Base):
    def __init__(self): pass
    __new__ = object.__new__

class Free:
    def __init__(self): pass
    __new__ = object.__new__

 >>> object.__new__(Free, *range(10), **{f'a{i}': i for i in range(10)})
<__main__.Free object at 0x000001E7B15C5A90>
>>> object.__new__(Sub, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: object.__new__() takes exactly one argument (the type to instantiate)

Sub 和 Free 都没有自定义 __new__ 方法 - 在两个类中 __new__object.__new__() 。但是创建 Sub 会引发错误,而创建 Free 则不会。似乎 object.__new__() 检查不 getattr(A_Class, '__new__', object.__new__) is object.__new__all(getattr(cls, '__new__', object.__new__) is object.__new__ for cls in A_Class.mro())


结论

  1. 如果一个类在其 MRO 中具有自定义 __new__ ,则使用 >1 个参数调用 object.__new__() 会引发 TypeError。
  2. 如果一个类在其 MRO 中只有自定义 __init__ 并且没有自定义 __new__ ,则调用 object.__new__() 会创建一个带有 >1 参数的属性
  3. 如果一个类在其 MRO 中没有同时自定义 __init____new__ ,则调用 object.__new__() 使用 >1 个参数引发 TypeError.

原文由 Svyatoslav 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题