11

Why does the following code work fine in Python 2.x and not in Python 3.3+:

class TestA(object):
    def __new__(cls, e):
        return super(TestA, cls).__new__(TestB, e)

class TestB(TestA):
    def __init__(self, e):
        print(self, e)

TestA(1)

Python 2.7.6 output:

(<__main__.TestB object at 0x7f6303378ad0>, 1)

Python 3.1.5 output:

__main__:3: DeprecationWarning: object.__new__() takes no parameters
<__main__.TestB object at 0x7f2f69db8f10> 1

Python 3.2.3 and 3.2.5 output:

<__main__.TestB object at 0xcda690> 1

Python 3.3.5 and 3.4.1 output:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __new__
TypeError: object() takes no parameters
4
  • 3
    Related: Why does object.__new__ work differently in these three cases Commented Jul 1, 2014 at 14:37
  • It's interpretator output, first print, second object. If run as program will one line. Fixed. Commented Jul 1, 2014 at 14:42
  • Are you sure ? This code work on Python 2.7.4 and Python 3.2.3. Commented Jul 1, 2014 at 14:42
  • For 3.2.3 work fine, updated post. Commented Jul 1, 2014 at 14:52

2 Answers 2

9

object.__new__ has always ignored extra arguments, and has issued a DeprecationWarning at least since Python 2.6.

The reason why you aren't seeing the DeprecationWarning in 2.7 and 3.2 is that since 2.7 and 3.2 DeprecationWarning has been suppressed by default; if you use python -Wd or PYTHONWARNINGS=default then you will see the warning.

In Python 3.3 the DeprecationWarning was converted to an error.

The correct way to write your code (in any version of Python) is to swallow the extra argument in TestA.__new__:

class TestA(object):
    def __new__(cls, e):
        return super(TestA, cls).__new__(TestB)

Since TestB is derived from TestA, the extra argument will be passed to TestB.__init__.

Sign up to request clarification or add additional context in comments.

1 Comment

Note that the Python documentation is silent about what to do with the extra arguments in an implementation of __new__(). It just states that these are the arguments "passed to the object constructor expression (the call to the class)", but it does not mention the DeprecationWarning or error described in the answer above (which I think is correct).
1

You can move the __init__ function to TestA like so:

class TestA(object):
    def __new__(cls, e):
        return super(TestA, cls).__new__(TestA)

    def __init__(self, e):
        print(self, e)

TestA(1)

Notice how TestB is not required.

Notice how the 'e' parameter is omitted from the call to object.__new__. The new function of object class only takes a class as parameter and any additional parameters in the overloaded __new__ function (in this case that of class TestA) is automatically passed to the constructor function (__init__) of the classed passed to object.__new__ (which in this case is also TestA).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.