¿No es posible definir múltiples constructores en Python? [duplicate]

5 minutos de lectura

avatar de usuario
cris

Posible duplicado:

¿Cuál es una forma pitónica limpia de tener múltiples constructores en Python?

¿No es posible definir múltiples constructores en Python, con diferentes firmas? Si no, ¿cuál es la forma general de evitarlo?

Por ejemplo, supongamos que desea definir una clase City.

me gustaria poder decir someCity = City() o someCity = City("Berlin")donde el primero solo proporciona un valor de nombre predeterminado y el segundo lo define.

  • Hazme pensar en esta pregunta – stackoverflow.com/questions/682504/…

    – Gante

    29 de enero de 2010 a las 18:49

  • Lo mejor: cómo sobrecargar __init__ método basado en el tipo de argumento?

    –Bob Stein

    30 de junio de 2017 a las 1:52


  • Esta pregunta es engañosa en base a la relación del título y el cuerpo. Peor aún, parece ser la respuesta principal en Google; Desearía que se editara o eliminara, ya que la pregunta en el cuerpo es realmente básica. Las respuestas al título se pueden encontrar en el posible enlace duplicado.

    – John Smith

    23 de julio de 2019 a las 14:57

A diferencia de Java, no puede definir múltiples constructores. Sin embargo, puede definir un valor predeterminado si no se pasa uno.

def __init__(self, city="Berlin"):
  self.city = city

avatar de usuario
mzz

Si sus firmas difieren sólo en el número de argumentos, usar argumentos predeterminados es la forma correcta de hacerlo. Si quieres poder pasar en diferentes tipos de argumento, trataría de evitar la isinstancebasado en el enfoque mencionado en otra respuesta, y en su lugar use argumentos de palabras clave.

Si usar solo argumentos de palabras clave se vuelve difícil de manejar, puede combinarlo con métodos de clase (al código bzrlib le gusta este enfoque). Este es solo un ejemplo tonto, pero espero que entiendas la idea:

class C(object):

    def __init__(self, fd):
        # Assume fd is a file-like object.
        self.fd = fd

    @classmethod
    def from_filename(cls, name):
        return cls(open(name, 'rb'))

# Now you can do:
c = C(fd)
# or:
c = C.from_filename('a filename')

Observe que todos esos métodos de clase siguen pasando por lo mismo __init__pero usar métodos de clase puede ser mucho más conveniente que tener que recordar qué combinaciones de argumentos de palabras clave __init__ trabajar.

isinstance es mejor evitarlo porque el tipo de pato de Python hace que sea difícil averiguar qué tipo de objeto se pasó realmente. Por ejemplo: si desea tomar un nombre de archivo o un objeto similar a un archivo, no puede usar isinstance(arg, file)porque hay muchos objetos similares a archivos que no subclasifican file (como los devueltos por urllib, o StringIO, o…). Por lo general, es una mejor idea que la persona que llama le diga explícitamente a qué tipo de objeto se refería, mediante el uso de diferentes argumentos de palabras clave.

  • Como usted dice, este es un gran enfoque si necesita pasar diferentes tipos de argumentos. En esos casos tiendo a usar un muy básico __init__ y hacer más de un método de clase para cada caso.

    – zekel

    26/09/2016 a las 22:20

  • esta es la solución más generalmente aplicable

    – Guilherme de Lázari

    13 de abril de 2018 a las 14:36

  • hay una buena manera (su recomendación) para no ejecutar el habitual __init__ función del segundo constructor? por ejemplo, porque ambos construirán el objeto desde cero

    – ThorSummoner

    23 de abril de 2019 a las 22:21


avatar de usuario
pavpanchekha

Para el ejemplo que diste, usa los valores predeterminados:

class City:
    def __init__(self, name="Default City Name"):
        ...
    ...

En general, tienes dos opciones:

  1. Hacer ifelif bloques basados ​​en el tipo:

    def __init__(self, name):
        if isinstance(name, str):
            # todo 
        elif isinstance(name, City):
            # todo 
        # todo 
    
  2. Use la tipificación de pato, es decir, suponga que el usuario de su clase es lo suficientemente inteligente como para usarlo correctamente. Esta suele ser la opción preferida.

avatar de usuario
Telliott99

La respuesta de Jack M. es correcta. Hacerlo de esta forma:

>>> class City:
...     def __init__(self, city=None):
...         self.city = city
...     def __repr__(self):
...         if self.city:  return self.city
...         return ''
...
>>> c = City('Berlin')
>>> print c
Berlin
>>> c = City()
>>> print c

>>>

avatar de usuario
jack m

La forma más fácil es a través de argumentos de palabras clave:

class City():
  def __init__(self, city=None):
    pass

someCity = City(city="Berlin")

Esto es algo bastante básico. tal vez mira la documentación de Python?

  • errores tipográficos en los comentarios; Además, esa no es la pregunta que hizo: preguntó sobre cambiar tipos, solo proporcionó un mal ejemplo.

    – pavpanchekha

    29 de enero de 2010 a las 18:42

  • @pavpanchekha: es exactamente lo que se preguntó. excepto por supuesto que falta self.

    – Fantasma silencioso

    29 de enero de 2010 a las 18:43


  • @Jack, tu ejemplo en realidad no almacena city en cualquier lugar tampoco, por lo que para un novato esta podría ser una respuesta bastante confusa.

    –Peter Hansen

    29 de enero de 2010 a las 19:30

  • errores tipográficos en los comentarios; Además, esa no es la pregunta que hizo: preguntó sobre cambiar tipos, solo proporcionó un mal ejemplo.

    – pavpanchekha

    29 de enero de 2010 a las 18:42

  • @pavpanchekha: es exactamente lo que se preguntó. excepto por supuesto que falta self.

    – Fantasma silencioso

    29 de enero de 2010 a las 18:43


  • @Jack, tu ejemplo en realidad no almacena city en cualquier lugar tampoco, por lo que para un novato esta podría ser una respuesta bastante confusa.

    –Peter Hansen

    29 de enero de 2010 a las 19:30

¿Ha sido útil esta solución?