Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #103805 > unrolled thread

What arguments are passed to the __new__ method ?

Started by"ast" <nomail@invalid.com>
First post2016-03-01 18:24 +0100
Last post2016-03-02 11:26 -0700
Articles 9 — 7 participants

Back to article view | Back to comp.lang.python


Contents

  What arguments are passed to the __new__ method ? "ast" <nomail@invalid.com> - 2016-03-01 18:24 +0100
    Re: What arguments are passed to the __new__ method ? eryk sun <eryksun@gmail.com> - 2016-03-01 13:54 -0600
    Re: What arguments are passed to the __new__ method ? Terry Reedy <tjreedy@udel.edu> - 2016-03-01 15:27 -0500
    Re: What arguments are passed to the __new__ method ? eryk sun <eryksun@gmail.com> - 2016-03-01 15:09 -0600
    Re: What arguments are passed to the __new__ method ? "ast" <nomail@invalid.com> - 2016-03-02 10:23 +0100
      Re: What arguments are passed to the __new__ method ? Steven D'Aprano <steve@pearwood.info> - 2016-03-02 22:02 +1100
    Re: What arguments are passed to the __new__ method ? Peter Pearson <pkpearson@nowhere.invalid> - 2016-03-02 17:40 +0000
      Re: What arguments are passed to the __new__ method ? Rob Gaddi <rgaddi@highlandtechnology.invalid> - 2016-03-02 17:57 +0000
        Re: What arguments are passed to the __new__ method ? Ian Kelly <ian.g.kelly@gmail.com> - 2016-03-02 11:26 -0700

#103805 — What arguments are passed to the __new__ method ?

From"ast" <nomail@invalid.com>
Date2016-03-01 18:24 +0100
SubjectWhat arguments are passed to the __new__ method ?
Message-ID<56d5d043$0$632$426a74cc@news.free.fr>
Hello

It's not clear to me what arguments are passed to the
__new__ method. Here is a piece of code:


class Premiere:

    def __new__(cls, price):
         return object.__new__(cls)

    def __init__(self, price):
            pass

p = Premiere(1000)

No errors, so it seems that 2 arguments are passed
to __new__, cls and price.


But if i do:


class Premiere:

    def __new__(cls, price):
        return object.__new__(cls, price)

    def __init__(self, price):
        pass

p = Premiere(1000)


it fails. It is strange because according to me it is equivalent to:


class Premiere:

    def __init__(self, price):
         pass

p = Premiere(1000)


which is OK.



[toc] | [next] | [standalone]


#103818

Fromeryk sun <eryksun@gmail.com>
Date2016-03-01 13:54 -0600
Message-ID<mailman.79.1456862114.20602.python-list@python.org>
In reply to#103805
On Tue, Mar 1, 2016 at 11:24 AM, ast <nomail@invalid.com> wrote:
>
> class Premiere:
>
>    def __new__(cls, price):
>        return object.__new__(cls, price)
>
>    def __init__(self, price):
>        pass
>
> p = Premiere(1000)
>
> it fails. It is strange because according to me it is equivalent to:
>
> class Premiere:
>
>    def __init__(self, price):
>         pass
>
> p = Premiere(1000)

The implementation knowns whether a type overrides the __new__ or
__init__ methods. You're expected to consume additional arguments in
this case. However, excess arguments are ignored in object.__new__ if
a type overrides __init__ without overriding __new__ (i.e. your second
example). Excess arguments are also ignored in object.__init__ if a
type overrides __new__ without overriding __init__.

In CPython, this behavior is implemented for object.__new__ by the
following statement in Objects/typeobject.c, object_new:

    if (excess_args(args, kwds) &&
        (type->tp_init == object_init ||
         type->tp_new != object_new)) {
        PyErr_SetString(PyExc_TypeError,
                        "object() takes no parameters");
        return NULL;
    }

An exception is always raised if a type overrides __new__ and passes
extra arguments to object.__new__. No exception is raised for excess
arguments in object.__new__ if a type overrides __init__ but not
__new__. The __init__ method must consume the extra arguments; it must
not pass them to object.__init__.

The behavior for object.__init__ is implemented by the following
statement in Objects/typeobject.c, object_init:

    if (excess_args(args, kwds) &&
        (type->tp_new == object_new ||
         type->tp_init != object_init)) {
        PyErr_SetString(PyExc_TypeError,
                        "object.__init__() takes no parameters");
        err = -1;
    }

An exception is always raised if a type overrides __init__ and passes
extra arguments to object.__init__. No exception is raised for excess
arguments in object.__init__ if a type overrides __new__ but not
__init__. The __new__ method must consume the extra arguments; it must
not pass them to object.__new__.

[toc] | [prev] | [next] | [standalone]


#103820

FromTerry Reedy <tjreedy@udel.edu>
Date2016-03-01 15:27 -0500
Message-ID<mailman.80.1456864099.20602.python-list@python.org>
In reply to#103805
On 3/1/2016 12:24 PM, ast wrote:
> Hello
>
> It's not clear to me what arguments are passed to the
> __new__ method.

The objects passed to any function are the objects that are passed.  The 
type and number of objects that *should be* passed depends on the 
signature of the function.

If class C defines __new__, then C.__new__ will receive as args C and 
all args passed in a C(...) call.  So the C(...) call should have args 
that match those expected by __new__.  If C also defines __init__, it 
will get the same args other than self replacing cls and thus it should 
have the same signature.

The case is covered by in the entry for __new__ in
https://docs.python.org/3/reference/datamodel.html#basic-customization

"If __new__() returns an instance of cls, then the new instance’s 
__init__() method will be invoked like __init__(self[, ...]), where self 
is the new instance and the remaining arguments are the same as were 
passed to __new__()."

> class Premiere:
>     def __new__(cls, price):
>          return object.__new__(cls)

This matches "Typical implementations create a new instance of the class 
by invoking the superclass’s __new__() method using super(currentclass, 
cls).__new__(cls[, ...]) with appropriate arguments and then modifying 
the newly-created instance as necessary before returning it." 
object.__new__ only takes the cls parameter.

>     def __init__(self, price):
>             pass
> p = Premiere(1000)
>
> No errors, so it seems that 2 arguments are passed
> to __new__, cls and price,

and 2 arguments are passed to __init__, self and price -- as documented.

> But if i do:

> class Premiere:
>     def __new__(cls, price):
>         return object.__new__(cls, price)

You get an error in current python because you sent an extra arg to 
object.__new__.  If __new__ calls a superclass __new__, then it should 
only pass the args expected.  At one time, object.__new__ would have 
accepted the price arg and ignored it.  This is no longer true

>     def __init__(self, price):
>         pass
> p = Premiere(1000)
>
> it fails. It is strange because according to me it is equivalent to:

Well, 'you' is wrong ;-), because in the following case, 
Premiere.__new__ is object.__new__, which has a different signature than 
__new__ above.

> class Premiere:
>     def __init__(self, price):
>          pass
> p = Premiere(1000)
>
> which is OK.

Premiere is callable because it inherits object.__call__.  That 
function, or the implementation of the CALL FUNCTION bytecode, must 
notice that Premiere.__new__ is object.__new__, by inheritance, and only 
pass Premiere and not 1000.

The doc entry for __init__ says "The arguments are those passed to the 
class constructor expression."  (The latter is the expression in the 
code that results in the class call.)  This is always true.  But since 
the signature of object.__new__ was restricted, the claim that the same 
args are sent to __new__ and __init__ seems not to be true.

I may open a new doc issue.

-- 
Terry Jan Reedy

[toc] | [prev] | [next] | [standalone]


#103821

Fromeryk sun <eryksun@gmail.com>
Date2016-03-01 15:09 -0600
Message-ID<mailman.83.1456866603.20602.python-list@python.org>
In reply to#103805
On Tue, Mar 1, 2016 at 2:27 PM, Terry Reedy <tjreedy@udel.edu> wrote:
> On 3/1/2016 12:24 PM, ast wrote:
>
>> class Premiere:
>>     def __init__(self, price):
>>          pass
>> p = Premiere(1000)
>>
>> which is OK.
>
> Premiere is callable because it inherits object.__call__.  That function, or
> the implementation of the CALL FUNCTION bytecode, must notice that
> Premiere.__new__ is object.__new__, by inheritance, and only pass Premiere
> and not 1000.

It's not handled in bytecode or __call__. In CPython the type_call
function passes its args and kwds to the type's tp_new and tp_init
functions without modification. object.__new__ ignores the excess
arguments in this case, as described in my previous message.

While I think the cases where object.__new__ and object.__init__
ignore excess arguments are practical and sensible, they should still
be documented. AFAICT, the language reference has nothing to say on
this matter.

[toc] | [prev] | [next] | [standalone]


#103850

From"ast" <nomail@invalid.com>
Date2016-03-02 10:23 +0100
Message-ID<56d6b12f$0$3663$426a74cc@news.free.fr>
In reply to#103805
"ast" <nomail@invalid.com> a écrit dans le message de news:56d5d043$0$632$426a74cc@news.free.fr...

ty  for the détailed explanations.


An other question:

What is the very first method launched when an instantiation is done ?
e.g  obj = MyClass(0, 5, 'xyz')

is it __call__ (from object or MyClass if overriden) ?
then _call__ launches __new__ and then __init__
This would be coherent with the language

or is it __new__ then __init__ as said on courses I read ?



[toc] | [prev] | [next] | [standalone]


#103861

FromSteven D'Aprano <steve@pearwood.info>
Date2016-03-02 22:02 +1100
Message-ID<56d6c84f$0$1621$c3e8da3$5496439d@news.astraweb.com>
In reply to#103850
On Wed, 2 Mar 2016 08:23 pm, ast wrote:


> An other question:
> 
> What is the very first method launched when an instantiation is done ?
> e.g  obj = MyClass(0, 5, 'xyz')
> 
> is it __call__ (from object or MyClass if overriden) ?

No, not object or MyClass. The *metaclass* __call__ is called.

For most objects, the metaclass is `type`.

The metaclass is the type of the class: classes are objects too, which means
that like all objects, they have a class. That is the metaclass.


*** WARNING ***

Metaclasses are a very advanced technique. You are not expected to
understand this.



> then _call__ launches __new__ and then __init__
> This would be coherent with the language
> 
> or is it __new__ then __init__ as said on courses I read ?

Let us create a metaclass that inherits from `type`:



class Meta(type):
    def __new__(meta, name, bases, namespace):
        print "**Creating new Meta instance"
        print "Metaclass:", meta
        print "New class name:", name
        print "Base classes used:", bases
        print "Namespace used as class dict:", namespace
        return type.__new__(meta, name, bases, namespace)
    def __init__(cls, *args):
        print "**Initialising Meta instance %s" % cls
    def __call__(cls):
        print "**Calling Meta instance %s" % cls
        return super(Meta, cls).__call__()



Now let me use that metaclass to create a new class:

class MyClass(object):
    __metaclass__ = Meta
    def __new__(cls):
        print "^^Creating new instance of %s" % cls
        return super(MyClass, cls).__new__(cls)
    def __init__(self):
        print "^^Initialising MyClass instance %s" % self
    def __call__(self):
        print "^^Calling MyClass instance %s" % self
        return "Hello World!"



which prints:

**Creating new Meta instance
Metaclass: <class '__main__.Meta'>
New class name: MyClass
Base classes used: (<type 'object'>,)
Namespace used as class dict: {'__call__': <function __call__ at
0xb7cfdf7c>, '__module__': '__main__', '__metaclass__':
<class '__main__.Meta'>, '__new__': <function __new__ at
0xb7cfdf0c>, '__init__': <function __init__ at 0xb7cfdf44>}
**Initialising Meta instance <class '__main__.MyClass'>


Now let me create a new MyClass instance:

instance = MyClass()


which prints:

**Calling Meta instance <class '__main__.MyClass'>
^^Creating new instance of <class '__main__.MyClass'>
^^Initialising MyClass instance <__main__.MyClass object at 0xb7cf2bec>


Finally, let me call the instance:

print instance()



which prints:


^^Calling MyClass instance <__main__.MyClass object at 0xb7cf2bec>
Hello World!



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#103887

FromPeter Pearson <pkpearson@nowhere.invalid>
Date2016-03-02 17:40 +0000
Message-ID<djoms1F1q2aU2@mid.individual.net>
In reply to#103805
On Tue, 1 Mar 2016 18:24:12 +0100, ast wrote:
>
> It's not clear to me what arguments are passed to the
> __new__ method. Here is a piece of code:
>
>
> class Premiere:
>
>     def __new__(cls, price):
>          return object.__new__(cls)
>
>     def __init__(self, price):
>             pass
[snip]

Of course, maybe you don't need to define a __new__ method at all.
Personally, I find that __init__ suffices for my simple needs.

-- 
To email me, substitute nowhere->runbox, invalid->com.

[toc] | [prev] | [next] | [standalone]


#103890

FromRob Gaddi <rgaddi@highlandtechnology.invalid>
Date2016-03-02 17:57 +0000
Message-ID<nb79hd$joh$1@dont-email.me>
In reply to#103887
Peter Pearson wrote:

> On Tue, 1 Mar 2016 18:24:12 +0100, ast wrote:
>>
>> It's not clear to me what arguments are passed to the
>> __new__ method. Here is a piece of code:
>>
>>
>> class Premiere:
>>
>>     def __new__(cls, price):
>>          return object.__new__(cls)
>>
>>     def __init__(self, price):
>>             pass
> [snip]
>
> Of course, maybe you don't need to define a __new__ method at all.
> Personally, I find that __init__ suffices for my simple needs.
>

I tend to need __init__ on about half of the classes I write.  I think
I've needed __new__ all of twice in the years I've been writing Python.

-- 
Rob Gaddi, Highland Technology -- www.highlandtechnology.com

Email address domain is currently out of order.  See above to fix.

[toc] | [prev] | [next] | [standalone]


#103892

FromIan Kelly <ian.g.kelly@gmail.com>
Date2016-03-02 11:26 -0700
Message-ID<mailman.109.1456943239.20602.python-list@python.org>
In reply to#103890
On Wed, Mar 2, 2016 at 10:57 AM, Rob Gaddi
<rgaddi@highlandtechnology.invalid> wrote:
> Peter Pearson wrote:
>
>> On Tue, 1 Mar 2016 18:24:12 +0100, ast wrote:
>>>
>>> It's not clear to me what arguments are passed to the
>>> __new__ method. Here is a piece of code:
>>>
>>>
>>> class Premiere:
>>>
>>>     def __new__(cls, price):
>>>          return object.__new__(cls)
>>>
>>>     def __init__(self, price):
>>>             pass
>> [snip]
>>
>> Of course, maybe you don't need to define a __new__ method at all.
>> Personally, I find that __init__ suffices for my simple needs.
>>
>
> I tend to need __init__ on about half of the classes I write.  I think
> I've needed __new__ all of twice in the years I've been writing Python.

Typically there are only two reasons to override __new__: you
potentially want to return an object of a different class than the
class that was called, or you're subclassing an immutable type and
need to handle the superclass arguments before they get passed to the
constructor.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web