GIZ
GIZ

Reputation: 4633

What is the downside of using object.__new__ in __new__?

Coding exception classes, I came across this error:

TypeError: object.__new__(A) is not safe, use Exception.__new__()

There's a similar question posted here: TypeError: object.__new__(int) is not safe, use int.__new__(). So __new__ was deprecated for the following reason:

[Python-Dev] __new__ deprecation

Guido van Rossum

"The message means just what it says. :-) There's no point in calling object.__new__() with more than a class parameter, and any code that did so was just dumping those args into a black hole."

But the warning in 3.3 that I get "is not safe" is scary. I try to understand the implication of using object.__new__, let's consider this example:

>>> class A(Exception):
...     def __new__(cls, *args):
...             return object.__new__(A)
...
>>> A()
TypeError: object.__new__(A) is not safe, use Exception.__new__()

Fails miserably. Another Example:

>>> class A(object):
...     def __new__(cls, *args):
...             return object.__new__(A)
...
>>>
>>> A()
<__main__.A object at 0x0000000002F2E278>

works fine. Although, object is a builtin class just like Exception with respect to their roles, they share the trait of being builtin-classes. Now with Exception, the first example raises TypeError, but with object, it does not?

(a) What are the downsides of using object.__new__ that made Python to raise the error (TypeError:...is not safe...) in the first Example?

(b) What sort of checking Python performs before to calling __new__? Or: What is the condition that makes Python raise the error in the first example?

Upvotes: 8

Views: 3518

Answers (2)

zvone
zvone

Reputation: 19352

There is no problem in calling object.__new__, but there is a problem in not calling Exception.__new__.

Exception class was designed in such way that it is crucial that its __new__ must be called, so it complains if that is not done.

There was a question why this happens only with built-in classes. Python in fact does it with every class which is programmed to do that.

Here is a simplified poor-mans implementation of the same mechanism in a custom class:

class A(object):
    def __new__(cls):
        rtn = object.__new__(cls)
        rtn.new_called = True
        return rtn

    def __init__(self):
        assert getattr(self,'new_called',False), \
            "object.__new__ is unsafe, use A.__new__"

class B(A):
    def __new__(cls):
        return object.__new__(cls)

And now:

>>> A()
<__main__.A object at 0x00000000025CFF98>

>>> B()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in __init__
AssertionError: object.__new__ is unsafe, use A.__new__

As a side note, this example from the question actually has two errors:

>>> class A(Exception):
...     def __new__(cls, *args):
...             return object.__new__(A)

The first is that __new__ is called on object, thus ignoring Exception.__new__.

The other, just as severe is that A is passed to __new__ instead of cls, which hinders all classes inherited from A.

See this example:

class A(object):
    def __new__(cls):
        return object.__new__(A)  # The same erroneous line, without Exception

class B(A):
    pass

And now B() does not create an instance of B:

>>> B()
<__main__.A object at 0x00000000025D30B8>

Upvotes: 10

chepner
chepner

Reputation: 531075

Calling object.__new__(A) returns an instance of A, but does so without calling Exception.__new__() if it is defined.

Upvotes: 0

Related Questions