为什么对象.__ new__在这三种情况下工作不同 [英] Why does object.__new__ work differently in these three cases
问题描述
来自问题为什么对象.__ new__在这两种情况下的工作方式不同
作者对为什么不感兴趣, 。
我非常想了解为什么,特别是:
- p>为什么不是
object .__ init __
不带任何参数打印而不是object .__ new__(在testclass1中)
p> -
为什么不为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 __ $ c $
这是为了支持不能用于 __ init __
的不可变类型将继承自 object
在这种情况下),和可变类型,其中 __ new __
不关心 __ init __
期望什么参数(通常会是更多个参数)。
请参阅问题1683368 ,其中Guido van Rossum解释了他的动机。
typeobject.c
源代码可以这样说:
您可能会想知道为什么
object .__ new __()
只有在引用object .__ init __()
时不会覆盖的参数
,反之亦然。
考虑用例:
当两者都不被覆盖时,我们想听到关于$ b $
当定义一个Immutable类型时,我们很可能会遇到一个错误。仅覆盖
__ new __()
,因为__ init __()
被调用太晚才能初始化
不可变对象。因为__ new __()
定义了
类型的签名,所以必须重写__ init __()$ c
在定义一个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 :
why isn't
object.__init__
takes no parameters printed instead ofobject.__new__ (in testclass1)
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
whenobject.__init__()
is not overridden, and vice versa.Consider the use cases:
When neither is overridden, we want to hear complaints about excess (i.e., any) arguments, since their presence could indicate there's a bug.
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.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.When
__init__()
is overridden, and the subclass__init__()
callsobject.__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屋!