为什么对象.__ new__在这三种情况下工作不同 [英] Why does object.__new__ work differently in these three cases

查看:159
本文介绍了为什么对象.__ new__在这三种情况下工作不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

来自问题为什么对象.__ new__在这两种情况下的工作方式不同



作者对为什么不感兴趣, 。



我非常想了解为什么,特别是:


  1. p>为什么不是 object .__ init __ 不带任何参数打印而不是 object .__ new__(在testclass1中) p>

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


代码

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

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

>>> a = object .__ new __(testclass1,56)
回溯(最近一次调用):
在< module>中第1行的文件< stdin&
TypeError:object .__ new __()不带参数

>>> 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对象在0x276a790>

>>>> c1 = object .__ new __(testclass3)

>>> c1
< __ main __。testclass3对象在0x276a810>


解决方案

错误讯息已更新:

 >>> object .__ new __(testclass1,56)
回溯(最近最后一次调用):
在< module>中第1行的文件< stdin&
TypeError:object()不带参数

Python只会报告<$ c $如果 __ new __ __ init __ 都未被覆盖,则c> __ init __ 例如当你从 object 继承它们。 testclass1 符合该情况, testclass3 不是因为它有 __ init __

这是为了支持不能用于 __ init __ 的不可变类型将继承自 object 在这种情况下),可变类型,其中 __ new __ 不关心 __ init __ 期望什么参数(通常会是更多个参数)。



请参阅问题1683368 ,其中Guido van Rossum解释了他的动机。



typeobject.c 源代码可以这样说:


您可能会想知道为什么 object .__ new __()只有在引用 object .__ init __()时不会覆盖的参数

,反之亦然。



考虑用例:


  1. 当两者都不被覆盖时,我们想听到关于$ b $


  2. 当定义一个Immutable类型时,我们很可能会遇到一个错误。仅覆盖
    __ new __(),因为 __ init __()被调用太晚才能初始化
    不可变对象。因为 __ new __()定义了
    类型的签名,所以必须重写 __ init __()


  3. 在定义一个Mutable类型时,我们可能只覆盖
    b __ init __()。所以这里的反向推理适用:我们不要
    想要重写 __ new __()只是为了阻止它从
    抱怨。 > c $> $ _ <$> $ <$> $ <$> $ <$> 调用
    object .__ init __(),后者应该抱怨过多的
    参数; ditto for __ new __()


使用案例2和3使得无条件检查
多余参数不具吸引力。解决所有四个使用
情况的最佳解决方案如下: __ init __()抱怨过多的参数
,除非 __ new __ )被覆盖,并且 __ init __()未被覆盖
(IOW,if __ init __ c $ c>被重写或 __ new __()不被覆盖);
对称, __ new __()抱怨过多的参数,除非
__ init __() __ new __()未被覆盖
(IOW,如果 __ new __()被覆盖或 __ init __()不会被覆盖。)



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


注意 .__ init__ ()方法本身仍然会报错!当你创建一个实例时, __ new __ __ init __ 您的代码只会直接调用 __ new __ ,并且不会 调用 __ init __ !如果您传递参数,则创建 testclass1 和 testclass3 的实例会失败:

 >>> testclass1(56)
回溯(最近一次调用):
在< module>中的文件< stdin&
TypeError:object()不带参数
>>> testclass3(56)
回溯(最近一次调用):
在< module>中的文件< stdin&
TypeError:__init __()只需要1个参数(给定2个)

对于 testclass1 ,它是 object()的默认方法,而不是自定义的特定错误 __ init __


from question Why does or rather how does object.__new__ work differently in these two cases

the author wasn't interested in the why, but rather in the how.

I would very much want to understand why, particularly :

  1. why isn't object.__init__ takes no parameters printed instead of object.__new__ (in testclass1)

  2. why no error is raised for testclass3 ? (as it takes no arguments other than self)

code

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

解决方案

You are using an older Python version; the error message has since been updated:

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

Python will only complain about __init__ not supporting arguments if neither __new__ nor __init__ have been overridden; e.g. when you inherit both from object. testclass1 fits that case, testclass3 does not because it has an __init__ method.

This is to support implementing immutable types that don't have a use for __init__ (which would be inherited from object in that case), and mutable types, where __new__ should not care about what arguments __init__ expects (which usually would be more arguments).

See issue 1683368 where Guido van Rossum explains his motivations for this.

The typeobject.c source code has this to say:

You may wonder why object.__new__() only complains about arguments
when object.__init__() is not overridden, and vice versa.

Consider the use cases:

  1. When neither is overridden, we want to hear complaints about excess (i.e., any) arguments, since their presence could indicate there's a bug.

  2. When defining an Immutable type, we are likely to override only __new__(), since __init__() is called too late to initialize an Immutable object. Since __new__() defines the signature for the type, it would be a pain to have to override __init__() just to stop it from complaining about excess arguments.

  3. When defining a Mutable type, we are likely to override only __init__(). So here the converse reasoning applies: we don't want to have to override __new__() just to stop it from complaining.

  4. When __init__() is overridden, and the subclass __init__() calls object.__init__(), the latter should complain about excess arguments; ditto for __new__().

Use cases 2 and 3 make it unattractive to unconditionally check for excess arguments. The best solution that addresses all four use cases is as follows: __init__() complains about excess arguments unless __new__() is overridden and __init__() is not overridden (IOW, if __init__() is overridden or __new__() is not overridden); symmetrically, __new__() complains about excess arguments unless __init__() is overridden and __new__() is not overridden (IOW, if __new__() is overridden or __init__() is not overridden).

However, for backwards compatibility, this breaks too much code. Therefore, in 2.6, we'll warn about excess arguments when both methods are overridden; for all other cases we'll use the above rules.

Note that the .__init__() method itself will still complain! When you create an instance, both __new__ and __init__ are called; your code only calls __new__ directly and does not invoke __init__! Creating an instance of testclass1 and testclass3 both fails if you pass in arguments:

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

The only difference is that for testclass1 it is the default methods for object() that complain instead a specific error for the custom __init__.

这篇关于为什么对象.__ new__在这三种情况下工作不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆