strategy software patterns pattern faif book python design-patterns initialization pep8

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 )