Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Python, how to avoid calling __init__ twice in a class derived from a class with super() in its __new__:

I am new to python. Somehow

__init__

is called twice for a class that is derived from another class using

super()

My question is how to avoid this because I have a very expensive computation there.

class A(object):
  def __new__(cls, *args, **kwargs):
    print("Class A: __new__")
    obj = super(A, cls).__new__(cls) # super is used here
    obj.__init__(*args, **kwargs)
    return obj
  def __init__(self, x):
    self.attrib = x+1

class B(A):
  def __init__(self, x):
    print("Class B: __init__")
    self.prop = 2*x # some expensive computation

a = A(10) # a test call

b = B(20) # Q: here, how to avoid calling __init__ twice in class B?

Edit: Thank you both for answers. My real code is diagonalising a large sparse matrix using arpack built in scipy library. I am calling a class SpLuInv(LinearOperator) defined in arpack.py where class LinearOperator is defined in interface.py, both files are attached: arpack.py and interface.py. When I call SpLuInv(), its init is called twice. From you answers, I think i need to remove obj.init that's in new of LinearOperator().

Thank you Brendan Abel for your answer and Akshat Mahajan and Mike Graham for your comments. Removing

obj.__init__

from the

__new__

of

LinearOperator()

solved the problem. :)

like image 448
Ahsan Zeb Avatar asked May 24 '16 02:05

Ahsan Zeb


1 Answers

You shouldn't manually call __init__ in __new__. The object returned from __new__ will automatically have __init__ called.

You should be calling the superclass __init__ in all your classes, even if they only inherit from object.

The only time this is a problem are for things like singleton objects, which often return an already __init__'d object from __new__. In that case, you just store the instance of the class as a class attribute and return directly from the __init__ if the attribute is set.

class A(object):
    def __new__(cls, *args, **kwargs):
        print("Class A: __new__")
        obj = super(A, cls).__new__(cls) # super is used here
        return obj

    def __init__(self, x):
        super(A, self).__init__()
        self.attrib = x+1

class B(A):
    def __init__(self, x):
        print("Class B: __init__")
        super(B, self).__init__(x)
        self.prop = 2*x # some expensive computation
like image 82
Brendan Abel Avatar answered Oct 21 '22 06:10

Brendan Abel