python - software - ¿Puede__init__ usarse como método normal de inicialización, no como constructor?
python software patterns (3)
A veces parece razonable usar __init__
como método de inicialización para un objeto ya existente, es decir:
class A():
def __init__(self, x):
self.x = x
def set_state_from_file(self, file):
x = parse_file(file)
self.__init__(x)
Como alternativa a esta implementación, veo lo siguiente:
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)
Me parece una sobrecomplicación de código. ¿Hay alguna directriz sobre esta situación?
Además de la respuesta de Martjin: un patrón común en Python es usar classmethods como métodos de fábrica, es decir:
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"))
Encontré algunas diferencias entre los métodos __init__
y ''normal'':
1., __init__
no puede devolver nada: TypeError se levantará.
2. Si __init__
provoca error, __del__
se llamará: ACTUALIZACIÓN por Martijn Pieters: esto es solo para llamadas de constructor, no para uso genérico, ver comentarios a continuación.
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'')
dará salida:
__init__
__init__ error
__del__
exit main
end of file
__init__
no es un constructor. Es un método de inicialización, llamado después de que la instancia ya haya sido construida para usted (el método real del constructor se llama __new__()
).
Siempre puede volver a llamar desde su código si necesita reinicializar, esto no es una violación de estilo. De hecho, se usa en la biblioteca estándar de Python; vea la implementación multiprocessing.heap.Heap()
por ejemplo:
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
o la implementación threading.local
, que utiliza un administrador de contexto para diferir la inicialización.
Por lo demás, no hay nada especial sobre el método __init__
. Simplemente se llama automáticamente por type.__call__
(después de crear la instancia con instance = cls.__new__(cls, *args, **kwargs)
, se instance = cls.__new__(cls, *args, **kwargs)
cls.__init__(instance, *args, **kwargs)
si está disponible )