Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does sympy override `__new__` instead of `__init__`?

Tags:

python

Every object in sympy is a subclass of the Basic class, and they all use __new__ without __init__, and mostly it's something like

def __new__(cls, some, parameter, **others):
    obj = parentclass.__new__(cls, **others)
    obj.some = some
    obj.parameter = parameter
    return obj

What's the difference to using __init__ like

def __init__(self, some, parameter, **others):
    parentclass.__init__(self, **others)  # or super().__init__(...)
    self.some = some
    self.parameter = parameter

?

like image 693
Tobias Kienzler Avatar asked Apr 10 '13 14:04

Tobias Kienzler


1 Answers

Have a look at Number . They want the class of the object to be flexible. Number(...) => Int/Float/... which can not be achieved by __init__.

Furthermore the __init__ would get the arguments of __new__ but you do not need the original arguments, see matexpr.py or you need them to be adapted to what __new__ already did (for example for __reduce__).

Most object define their own __slots__ so there are fixed attributes that can be assigned to them. Assignment can be done in __new__ and __init__. I do not see the need to open a new __init__ for just setting them and doing no other operations - As Martijn Pieters and user4815162342 [source] pointed out the objects are immutable.

Sometimes __init__ is called not, once or twice if you change the class:

class X(object):
    def __new__(self): # sorry but self is the class I apologize!
        obj = object.__new__(Y)
        return obj
    def __init__(self):
        print 1

>>> class Y(object):
    def __init__(self):
        print 2
>>> X() # no __init__ call, limiting you to stay in the class hierarchy
<__main__.Y object at 0x7f287e769350>
>>> class Y(X):
    def __init__(self):
        print 2


>>> X() # one __init__ call
2
<__main__.Y object at 0x7f287e7693d0>
>>> class X(object):
    def __new__(self):
        obj = Y()
        return obj
    def __init__(self):
        print 1


>>> class Y(X):
    def __new__(self):
        return object.__new__(self)
    def __init__(self):
        print 2


>>> X() # __init__ called twice, structure copied from number.py
2
2
<__main__.Y object at 0x7f287e7692d0>

Correct me if I am wrong. I do not think this answer is complete but these are complications I found worth motivating to not use __init__ additionally to that the objects should be immutable as mentioned by Martijn Pieters and user4815162342 [source]

Waiting for 2 downvotes to delete the answer.

like image 133
User Avatar answered Sep 20 '22 08:09

User