Title: Python __new__ method doc typo (it's a class and not a static method)
Type: enhancement Stage:
Components: Documentation Versions: Python 3.5
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: docs@python Nosy List: Jurko.Gospodnetić, docs@python, eric.snow, eryksun, jcea, steven.daprano
Priority: normal Keywords: patch

Created on 2014-05-02 10:29 by Jurko.Gospodnetić, last changed 2014-05-13 01:03 by eric.snow. This issue is now closed.

File name Uploaded Description Edit
81c5ba188805.diff Jurko.Gospodnetić, 2014-05-02 10:31 patch collected from BitBucket's jurko/cpython repo review
Repositories containing patches
Messages (5)
msg217748 - (view) Author: Jurko Gospodnetić (Jurko.Gospodnetić) * Date: 2014-05-02 10:29
Doc/reference/datamodel.rst documentation states that
the __new__ method is a static method (in Python, not
in C!) when it is in fact a class method.

A patch has been prepared in the repository.
branch: datamodel_doc_typo_fix
commit: 81c5ba188805e42292c3eb9cffa56fbd5b7c6aee

But it'll probably be easier for you to just change
that single word directly. :-D

Hope this helps.

Best regards,
  Jurko Gospodnetić
msg217749 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2014-05-02 12:07
Actually, no, it is a staticmethod. See Guido's tutorial from way back in version 2.2:

__new__ is a static method. When defining it, you don't need to (but may!) use the phrase "__new__ = staticmethod(__new__)", because this is implied by its name (it is special-cased by the class constructor).
[end quote]

I believe that this explains why you have to use this idiom inside __new__ when using super():

    def __new__(cls, x):
        super().__new__(cls, x)

If __new__ were a classmethod, the first argument "cls" would be provided automatically.

If you try making __new__ a classmethod, it breaks:

py> class Test:
...     @classmethod
...     def __new__(cls):
...             pass
py> x = Test()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __new__() takes 1 positional argument but 2 were given

whereas a staticmethod works fine.
msg217751 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2014-05-02 14:45
> I believe that this explains why you have to use this idiom 
> inside __new__ when using super():
>     def __new__(cls, x):
>         super().__new__(cls, x)

Yes, if __new__ is defined and is a function, type_new replaces it with a staticmethod:

For example:

    >>> class A: __new__ = lambda c: 0

    >>> type(vars(A)['__new__'])
    <class 'staticmethod'>

A heap type that defines __new__ has tp_new set to slot_tp_new. This looks up and calls __new__, with the class inserted as the first argument:

If you use a classmethod, looking up __new__ returns a method bound to the class. When called, this inserts the class in the args yet again:
msg217819 - (view) Author: Jurko Gospodnetić (Jurko.Gospodnetić) * Date: 2014-05-03 09:11
Thanks for the detailed response! :-(

I should have tested more before reporting the issue.
Sorry for the noise. :-(

I saw the 'cls' argument and assumed it was a class
method. Having to explicitly specify cls did not
seem to be in contradiction with this since I assumed
__new__ is generally invoked on the class directly.

I still do not see why it had to be a static method
and has not been implemented as a class method, but I
guess I'll better ask that kind of a question on the
python user's newsgroup. :-)

Just in case it can help someone else, here's some
sample code what convinced me __new__ was indeed
implemented as a static method:

> class X:
>     pass
> X.__new__()   # TypeError: object.__new__(): not enough arguments
> X.__new__(X)  # creates a new X instance
> x = X()
> x.__new__()   # TypeError: object.__new__(): not enough arguments
> x.__new__(X)  # creates a new X instance

If __new__ had been a class method then calling
'x.__new__()' would have worked as well.

Thanks again for the replies!

Best regards,
  Jurko Gospodnetić
msg218392 - (view) Author: Eric Snow (eric.snow) * (Python committer) Date: 2014-05-13 01:03
FYI, __new__() is a staticmethod to accommodate subclassing.  Several things that happen at instantiation-time (when __new__() is called), including memory allocation, are tied to the class that is passed in and may be different for subclasses.   For example:

class Spam(int):
    def __new__(cls, value):
        self = super().__new__(Spam, value)
        self._eggs = 10
        return self

Spam is passed in instead of int (as would happen if it were a classmethod), resulting in extra memory being allocated for _eggs (and for __dict__ among other things).
Date User Action Args
2014-05-13 01:03:38eric.snowsetnosy: + eric.snow
messages: + msg218392
2014-05-07 01:33:12jceasetnosy: + jcea
2014-05-03 09:11:13Jurko.Gospodnetićsetmessages: + msg217819
2014-05-02 14:45:24eryksunsetnosy: + eryksun
messages: + msg217751
2014-05-02 12:07:35steven.dapranosetstatus: open -> closed

nosy: + steven.daprano
messages: + msg217749

resolution: not a bug
2014-05-02 10:31:10Jurko.Gospodnetićsetfiles: + 81c5ba188805.diff
keywords: + patch
2014-05-02 10:29:56Jurko.Gospodnetićcreate