Why, or rather, how the .__ new__ object works differently in these two cases

Python version: "'2.7.3 (default, April 10, 2013 06:20:15) \ n [GCC 4.6.3]'"

I have it:

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

A bit more fun! Compare with testclass1 results above.

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

My question is how (and not why) object__new__ behave differently in these two cases? Also, pay attention to the error, which is misleading in the first case, because in the second case, object.__new__ ultimately takes an argument !.

+4
python object constructor
source share
3 answers

Both object.__new__ and object.__init__ go through a carefully designed labyrinth of conditions that in some cases allow redundant arguments, cause errors in others, and raise a warning in a very specific way. The code that performs the checks is simple enough to follow, but the reasoning behind this is likely to remain incomprehensible without this explanatory comment :

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

Consider the use cases:

  • If none of them is canceled, we want to hear complaints about unnecessary (i.e. any) arguments, since their presence may indicate an error.

  • When defining an immutable type, we will most likely only override __new__() , since __init__() is called too late to initialize an immutable object. Since __new__() defines the signature for the type, it would be painful to override __init__() to stop it complaining about unnecessary arguments.

  • When defining a Mutable type, we are likely to override only __init__() . So here the reverse reasoning applies: we do not want to override __new__() to stop it from complaining.

  • When __init__() overridden, and the subclass __init__() calls object.__init__() , the latter must complain about exceeding arguments; same for __new__() .

Using cases 2 and 3 makes it unacceptable to unconditionally check redundant arguments. The best solution covering all four use cases is as follows: __init__() complains about redundant arguments unless __new__() overridden and __init__() is overridden (IOW if __init__() overridden or __new__() not overridden); symmetrically, __new__() complains about redundant arguments unless __init__() redefined and __new__() is redefined (IOW if __new__() redefined or __init__() not redefined).

However, for backward compatibility, this redistributes the code too much. Therefore, in 2.6 we will warn of additional arguments when both methods are overridden; for all other cases, we will use the above rules.

+5
source share

The created class has a member __init__() , which is called by new() to process any creation parameters, but in the first case you do not have __init__ , so you cannot pass any parameters.

+3
source share

The __new__ static method takes a class as its first argument. Other arguments will be passed to this __init__ class. Since your class does not have a __init__ method, __new__ will not accept other arguments.

See the documentation for more information.

As for the how, it is implemented in C ( Objects/typeobject.c ), but you can do the same check with pure Python:

 def __new__(cls, *args, **kwargs): ... if not hasattr(cls, '__init__') and (args or kwargs): raise TypeError("object.__init__() takes no parameters") ... 
+3
source share

All Articles