May __init__ be used as normal method for initialization, not as constructor?

♀尐吖头ヾ 提交于 2020-05-28 21:55:04

问题


Sometimes it looks reasonable to use __init__ as initialization method for already existing object, i.e.:

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

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

As 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 as over-complication of code. Is there any guideline on this situation?


回答1:


__init__ is not a constructor. It is an initialisation method, called after the instance was already constructed for you (the actual constructor method is called __new__()).

You can always call it again from your code if you need to re-initialise, this isn't a style violation. In fact, it is used in the Python standard 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 the threading.local implementation, which uses a context manager to defer initialisation.

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




回答2:


In addition to Martjin's answer: a common pattern in Python is to use classmethods as factory methods, ie:

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"))



回答3:


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

1., __init__ is not allowed to return anything: TypeError will be raised.

2., If __init__ raises error, __del__ will be called: UPDATE by Martijn Pieters: this is only for constructor calls, not for generic usage, 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


来源:https://stackoverflow.com/questions/40588239/may-init-be-used-as-normal-method-for-initialization-not-as-constructor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!