问题
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