2010-01-29 260 views
112

Duplicar posibles:
What is a clean, pythonic way to have multiple constructors in Python?¿Múltiples constructores en python?

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

Por ejemplo, digamos que usted quiere definir una clase City

Me gustaría poder decir someCity = City() o someCity = City("Berlin"), donde el primer solo da un valor de nombre por defecto, y el segundo lo define.

+2

me hacen pensar en esta pregunta - http://stackoverflow.com/questions/682504/what-is-a-clean-pythonic-way-to-have-multiple -constructors-in-python – Gant

+0

Mejor: [¿Cómo sobrecargar el método '__init__' basado en el tipo de argumento?] (https://stackoverflow.com/questions/141545/how-to-overload-init-method-based-on- argumento-tipo) –

Respuesta

143

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 
2

La manera más fácil es a través de argumentos de palabra clave:

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

someCity = City(city="Berlin") 

Esto es bastante cosas básicas, tal vez mira the python docs?

+0

errores tipográficos en los comentarios; Además, esa no era la pregunta que hacía, preguntaba sobre el cambio de tipos, simplemente daba un mal ejemplo. – pavpanchekha

+1

@pavpanchekha: es exactamente lo que se pidió. excepto por supuesto que falta el "self". – SilentGhost

+5

@Jack, tu ejemplo tampoco almacena 'ciudad' en ninguna parte, por lo que para un novato esta podría ser una respuesta bastante confusa. –

2

por el ejemplo que dio, el uso de los valores por defecto:

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

En general, usted tiene dos opciones:

1) ¿if - elif bloques en función del tipo:

def __init__(self, name): 
    if isinstance(name, str): 
     ... 
    elif isinstance(name, City): 
     ... 
    ... 

2) Use pato de tipeo --- es decir, suponga que el usuario de su clase es lo suficientemente inteligente como para usarlo correctamente. Esta suele ser la opción preferida.

+0

@Ghost Valores predeterminados ... um ... Supongo que es eso. Punto a favor. ¿Por qué voté esto? Ah, mierda, el voto es demasiado viejo para cambiar ahora. –

140

Si sus firmas sólo se diferencian en el número de los argumentos que utilizan los argumentos por defecto es la forma correcta de hacerlo. Si desea poder pasar diferentes tipos de del argumento, trataría de evitar el enfoque basado en isinstance mencionado en otra respuesta, en lugar de usar argumentos de palabra clave. Si el uso de solo argumentos de palabra clave se vuelve difícil de manejar, puede combinarlo con classmethods (al código bzrlib le gusta este enfoque). Esto es sólo un ejemplo tonto, pero espero que la idea:

class C(object): 

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

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

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

Aviso todas esas classmethods siguen pasando por la misma __init__, pero utilizando classmethods pueden ser mucho más cómodo que tener que recordar qué combinaciones de argumentos de palabra clave a __init__ trabajo.

isinstance es mejor evitarlo porque la tipificación de pato del pitón hace que sea difícil averiguar qué tipo de objeto se pasa realmente en. Por ejemplo: si usted quiere tomar ya sea un nombre de archivo o un objeto de tipo fichero que no se puede utilizar isinstance(arg, file) porque hay hay muchos objetos similares a archivos que no incluyen la subclase file (como los devueltos desde urllib, o StringIO, o ...). Por lo general, es una mejor idea que la persona que llama le diga explícitamente qué tipo de objeto significa, utilizando diferentes argumentos de palabras clave.

+0

Como dices, este es un gran enfoque si necesitas pasar diferentes tipos de argumentos. En esos casos, tiendo a usar un '__init__' muy básico y hago más de un método de clase para cada caso. – zekel

2

Jack M.es correcto, hacerlo de esta manera:

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

>>> 
Cuestiones relacionadas