5

Python 版本:“'2.7.3(默认,2013 年 4 月 10 日,06:20:15)\n[GCC 4.6.3]'”

我有这个:

>>> class testclass1(object):
    ...     pass
    ... 

>>> class testclass2(object):
    ...     def __init__(self,param):
    ...             pass
    ... 

>>> a = object.__new__(testclass1, 56)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: object.__new__() takes no parameters

>>> b = object.__new__(testclass2, 56)

>>> b
    <__main__.testclass2 object at 0x276a5d0>

更有趣一些!与上面 testclass1 的结果进行比较。

>>> class testclass3(object):
    ...     def __init__(self):
    ...             pass
    ... 

>>> c = object.__new__(testclass3, 56)

>>> c
    <__main__.testclass3 object at 0x276a790>

>>> c1 = object.__new__(testclass3)

>>> c1
    <__main__.testclass3 object at 0x276a810>

我的问题是在这两种情况下(不是为什么)表现不同?object__new__另请注意,在第一种情况下,该错误有点误导,因为在第二种情况下object.__new__,最终确实会引起争论!。

4

3 回答 3

6

两者object.__new__object.__init__经过精心构建的条件迷宫,在某些情况下允许过多的参数,在其他情况下引发错误,并在非常具体的情况下引发警告。实现检查的代码很容易理解,但如果没有这个明确的注释,其背后的推理可能仍然难以理解:

你可能想知道为什么object.__new__()只有在没有被覆盖时才抱怨参数object.__init__(),反之亦然。

考虑用例:

  1. 当两者都没有被覆盖时,我们希望听到关于过多(即任何)参数的抱怨,因为它们的存在可能表明存在错误。

  2. 在定义 Immutable 类型时,我们可能只重写__new__(),因为__init__()调用太晚而无法初始化 Immutable 对象。由于__new__()定义了类型的签名,因此必须重写__init__()只是为了阻止它抱怨过多的参数是很痛苦的。

  3. 在定义 Mutable 类型时,我们可能只覆盖__init__(). 所以这里适用相反的推理:我们不想__new__()为了阻止它抱怨而重写。

  4. When__init__()被覆盖,子类__init__()调用object.__init__(),后者应该抱怨过多的参数;同上__new__()

用例 2 和 3 使得无条件检查多余参数变得没有吸引力。解决所有四个用例的最佳解决方案如下:__init__()抱怨过多的参数,除非 __new__()被覆盖__init__()且未被覆盖(IOW,如果 __init__()被覆盖或__new__()未被覆盖);对称地,__new__()抱怨过多的参数,除非 __init__()被覆盖并且__new__()未被覆盖(IOW,如果 __new__()被覆盖或__init__()未被覆盖)。

但是,为了向后兼容,这会破坏太多代码。因此,在 2.6 中,当两个方法都被覆盖时,我们会警告过多的参数;对于所有其他情况,我们将使用上述规则。

于 2013-09-08T14:44:58.630 回答
3

您正在创建的有其成员__init__()被调用new()来处理任何创建参数,但在第一种情况下,您没有__init__,所以不能传递任何参数。

于 2013-09-08T06:03:51.293 回答
3

静态方法将__new__类作为其第一个参数。其他参数将被传递到该类的__init__方法中。由于您的班级没有__init__方法,__new__因此不会接受其他参数。

查看文档以获取更多信息。

至于“如何”,它是在 C ( Objects/typeobject.c) 中实现的,但您可以使用纯 Python 执行相同的检查:

def __new__(cls, *args, **kwargs):
    ...

    if not hasattr(cls, '__init__') and (args or kwargs):
        raise TypeError("object.__init__() takes no parameters")

    ...
于 2013-09-08T06:04:01.870 回答