【问题标题】:Why does object.__new__ work differently in these three cases为什么 object.__new__ 在这三种情况下的工作方式不同
【发布时间】:2013-10-17 03:05:43
【问题描述】:

来自问题Why does or rather how does object.__new__ work differently in these two cases

作者对原因不感兴趣,而对方法感兴趣。

我非常想知道为什么,尤其是:

  1. 为什么object.__init__ 不打印参数而不是object.__new__ (in testclass1)

  2. 为什么没有为 testclass3 引发错误? (因为它除了 self 不需要任何参数)

代码

>>> 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>

>>> 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>

【问题讨论】:

  • 您是否阅读了this 对python 源代码的评论?他们决定在某些情况下引发错误以允许仅定义__init____new__ 之一。否则你总是不得不重新定义它们,即使它们是无操作的。
  • 我不明白:我只定义了 init,它不接受任何参数(显然除了 self),我将一个参数传递给 新的,为什么不报错?

标签: python object types constructor


【解决方案1】:

您使用的是较旧的 Python 版本;错误消息已更新:

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

如果__new____init__ 都没有被覆盖,Python 只会抱怨__init__ 不支持参数;例如当您从object 继承两者时。 testclass1 适合这种情况,testclass3 不适合,因为它有一个 __init__ 方法。

这是为了支持实现不使用 __init__(在这种情况下将从 object 继承)、可变类型的不可变类型,其中 __new__不应该关心__init__ 期望的参数(通常是更多个参数)。

请参阅 issue 1683368 Guido van Rossum 解释他这样做的动机。

typeobject.c source code 有话要说:

你可能想知道为什么object.__new__() 只抱怨争论
object.__init__() 未被覆盖时,反之亦然。

考虑用例:

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

  2. 在定义不可变类型时,我们可能只重写 __new__(),因为 __init__() 被调用太晚而无法初始化 不可变对象。由于__new__() 定义了 类型,必须重写 __init__() 只是为了 阻止它抱怨过多的论点。

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

  4. __init__() 被覆盖时,子类__init__() 调用 object.__init__(),后者应该抱怨多余 论据; __new__() 同上。

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

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

注意.__init__() 方法本身仍然会报错!创建实例时,__new____init__ 都会被调用;您的代码只直接调用__new__ 并且 调用__init__!如果传入参数,创建 testclass1testclass3 的实例都会失败:

>>> testclass1(56)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object() takes no parameters
>>> testclass3(56)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() takes exactly 1 argument (2 given)

唯一的区别是,对于 testclass1,它是 object() 的默认方法,它抱怨自定义 __init__ 的特定错误。

【讨论】:

    猜你喜欢
    • 2013-09-11
    • 2019-11-08
    • 1970-01-01
    • 2021-03-26
    • 1970-01-01
    • 2022-09-23
    • 2014-02-11
    • 2016-11-06
    相关资源
    最近更新 更多