Inconsistency when overriding object.__new__

Viewed 74

In both Python 2 and 3, the following code

class A(object):
    pass

A(1)

expectedly raises the following exception

TypeError: object() takes no parameters

However, the following code

class A(object):
    def __new__(cls, *args, **kwargs):
        return super(A, cls).__new__(cls)

A(1)

Does not raise anything. How come?

1 Answers

The answer lies in how object.__new__ [1] and object.__init__ [2] handle extra arguments.

Let's walk through a couple examples:

class A(object):
    pass

>>> A(1)
TypeError: object() takes no parameters
  • First, object.__new__ is called. It gets the 1 argument. We didn't override __new__ so this is false [1] and it doesn't throw an error. We didn't override __init__ so this is true [2] and throws an error.
class A(object):
    def __init__(self, *args, **kwargs):
        print("A.__init__({0}, {1}, {2})".format(self, args, kwargs))

>>> A(1)
A.__init__(<__main__.A object at 0xdeadbeef>, (1, ), {})
<__main__.A at 0xdeadbeef>
  • First, object.__new__ is called. It gets the 1 argument. We didn't override __new__ so this is false [3] and it doesn't throw an error. We did override __init__ so this is false [4] and doesn't throw an error.
  • Second, A.__init__ is called. Because it doesn't call super, object.__init__ is never called.
class A(object):
    def __new__(cls, *args, **kwargs):
        print("A.__new__({0}, {1}, {2})".format(cls, args, kwargs))
        return super(A, cls).__new__(cls)

>>> A(1)
A.__new__(<class '__main__.A'>, (1,), {})
<__main__.A at 0xdeadbeef>
  • First, A.__new__ is called. It gets the 1 argument. We call object.__new__ with no arguments.
  • Second, object.__init__ is called. It gets the 1 argument. We didn't override __init__ so this is false [5] and it doesn't throw an error. We did override __new__ so this is false [6] and it doesn't throw an error.

[1] https://github.com/python/cpython/blob/04fc4f2a46b2fd083639deb872c3a3037fdb47d6/Objects/typeobject.c#L3866

[2] https://github.com/python/cpython/blob/04fc4f2a46b2fd083639deb872c3a3037fdb47d6/Objects/typeobject.c#L3847

[3] https://github.com/python/cpython/blob/04fc4f2a46b2fd083639deb872c3a3037fdb47d6/Objects/typeobject.c#L3867

[4] https://github.com/python/cpython/blob/04fc4f2a46b2fd083639deb872c3a3037fdb47d6/Objects/typeobject.c#L3872

[5] https://github.com/python/cpython/blob/04fc4f2a46b2fd083639deb872c3a3037fdb47d6/Objects/typeobject.c#L3848

[6] https://github.com/python/cpython/blob/04fc4f2a46b2fd083639deb872c3a3037fdb47d6/Objects/typeobject.c#L3853

Related