web-dev-qa-db-fra.com

Plusieurs constructeurs en python?

Duplicate possible:
Qu'est-ce qu'une façon propre et pythonique d'avoir plusieurs constructeurs en Python?

N'est-il pas possible de définir plusieurs constructeurs en Python, avec des signatures différentes? Si non, quel est le moyen général de le contourner?

Par exemple, supposons que vous vouliez définir une classe City

J'aimerais pouvoir dire someCity = City() ou someCity = City("Berlin"), où le premier ne donne qu'une valeur de nom par défaut et le second la définit.

189
Chris

Contrairement à Java, vous ne pouvez pas définir plusieurs constructeurs. Cependant, vous pouvez définir une valeur par défaut si aucune n'est transmise.

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

Si vos signatures ne diffèrent que par nombre des arguments, les arguments par défaut sont la bonne façon de le faire. Si vous voulez pouvoir passer dans différents types d'arguments, j'essaierai d'éviter l'approche basée sur isinstance mentionnée dans une autre réponse, en utilisant plutôt des arguments de mots clés. Si utiliser uniquement des arguments de mots-clés devient compliqué, vous pouvez le combiner avec des méthodes de classe (le code bzrlib aime cette approche). Ceci est juste un exemple stupide, mais j'espère que vous avez l'idée:

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

Notez que toutes ces méthodes de classe suivent toujours le même __init__, mais utiliser des méthodes de classe peut être beaucoup plus pratique que de devoir mémoriser les combinaisons d'arguments de mot clé à utiliser pour __init__.

Il est préférable d'éviter isinstance car la saisie au moyen de python rend difficile la détermination du type d'objet réellement transmis. Par exemple: si vous souhaitez utiliser un nom de fichier ou un objet de type fichier, vous ne pouvez pas utiliser isinstance(arg, file) car il y a Il existe de nombreux objets de type fichier qui ne sont pas sous-classe file (comme ceux renvoyés par urllib, ou StringIO, ou ...). Il est généralement préférable de demander à l'appelant de vous indiquer explicitement le type d'objet utilisé, en utilisant des arguments de mots clés différents.

213
mzz

Pour l'exemple que vous avez donné, utilisez les valeurs par défaut:

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

En général, vous avez deux options:

1) Faites if-Elif blocs en fonction du type:

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

2) Utilisez un type de frappe - supposez que l'utilisateur de votre classe est suffisamment intelligent pour l'utiliser correctement. C'est typiquement l'option préférée.

7
pavpanchekha

Le moyen le plus simple consiste à utiliser des arguments de mots clés:

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

someCity = City(city="Berlin")

C'est assez basique, peut-être regardez le python docs ?

5
Jack M.

Jack M. a raison, procédez comme suit:

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

>>>
4
telliott99