Can __init__ be used as a normal method for initialization, and not as a constructor?

It is sometimes wise to use __init__ as an initialization method for an existing object, that is:

 class A(): def __init__(self, x): self.x = x def set_state_from_file(self, file): x = parse_file(file) self.__init__(x) 

As an alternative to this implementation, I see the following:

 class A(): def __init__(self, x): self.init(x) def init(self, x): self.x = x def set_state_from_file(self, file): x = parse_file(file) self.init(x) 

It seems to me that this is an overly complicated code. Are there any recommendations on this situation?

+7
python initialization design-patterns pep8
source share
3 answers

__init__ not a constructor. This is the initialization method called after the instance has already been created for you (the actual constructor method is called __new__() ).

You can always call it again from your code, if you need to reinitialize, this is not a style violation. In fact, it is used in the standard Python library; see the multiprocessing.heap.Heap() implementation , for example:

 def malloc(self, size): # return a block of right size (possibly rounded up) assert 0 <= size < sys.maxsize if os.getpid() != self._lastpid: self.__init__() # reinitialize after fork 

or a threading.local implementation that uses a context manager to delay initialization.

There is nothing special about the __init__ method itself. It is simply automatically called type.__call__ (after creating an instance with instance = cls.__new__(cls, *args, **kwargs) , cls.__init__(instance, *args, **kwargs) is called, if available).

+11
source share

In addition to Martjin's answer: a common pattern in Python is to use class methods as factory methods, i.e.:

 class A(): def __init__(self, x): self.x = x @classmethod def from_file(cls, file): x = parse_file(file) return cls(x) a1 = A(42) a2 = A.from_file(open("/path/to/file")) 
+4
source share

I found some differences between the __init__ and 'normal' methods:

1., __init__ cannot return anything: TypeError will be raised.

2. If __init__ causes an error, __del__ will be called: UPDATE by Martijn Pieters: this is only for constructor calls and not for general use, see Comments below.

  class A(object): def __init__(self): print('__init__') raise ValueError('__init__ error') pass def method(self): raise ValueError('method error') def __del__(self): print("__del__") def main(): try: a = A() a.method() except ValueError as e: print(e) print('exit main') if __name__ == '__main__': main() print('end of file') 

will output:

 __init__ __init__ error __del__ exit main end of file 
0
source share

All Articles