Fonctions surchargées en python?


91

Est-il possible d'avoir des fonctions surchargées en Python? En C #, je ferais quelque chose comme

void myfunction (int first, string second)
{
//some code
}
void myfunction (int first, string second , float third)
{
//some different code
}

et ensuite, lorsque j'appelle la fonction, elle différencie les deux en fonction du nombre d'arguments. Est-il possible de faire quelque chose de similaire en Python?


Cela semble être un message en double possible. Veuillez également ne pas marquer comme C # car la question n'a pas à voir avec C #. function-overloading-in-python-missing
Jethro

duplication possible de la surcharge
Li0liQ

Réponses:


103

EDIT Pour les nouvelles fonctions génériques de distribution unique dans Python 3.4, voir http://www.python.org/dev/peps/pep-0443/

Vous n'avez généralement pas besoin de surcharger les fonctions en Python. Python est typé dynamiquement et prend en charge les arguments facultatifs des fonctions.

def myfunction(first, second, third = None):
    if third is None:
        #just use first and second
    else:
        #use all three

myfunction(1, 2) # third will be None, so enter the 'if' clause
myfunction(3, 4, 5) # third isn't None, it's 5, so enter the 'else' clause

3
Mais notez que l'appel de différentes fonctions en fonction du type d'arguments est beaucoup plus difficile (mais pas impossible).
Andrew Jaffe

9
Eh bien, il y a une différence entre la surcharge / polymorphisme et les conditions. Voulez-vous dire que nous n'avons pas besoin du polymorphysme puisque nous avons les conditions?
Val

1
@Val Je dis, en gros, que dans un langage à typage dynamique, vous n'avez pas besoin de surcharger en tant que fonctionnalité de langage car vous pouvez l'émuler de manière triviale dans le code, et ainsi obtenir le polymorphisme de cette façon.
agf

1
@Val Je dis qu'entre les arguments optionnels et les types dynamiques tels que vous les avez en Python, vous n'avez pas besoin d'une surcharge de méthode de style Java pour obtenir un polymorphisme.
agf

3
@navidoo Je dirais que ce n'est pas une bonne idée - une fonction ne devrait pas renvoyer des types de choses complètement différents. Cependant, vous pouvez toujours définir une fonction de générateur local à l'intérieur de la fonction principale, l'appeler et renvoyer le générateur résultant - de l'extérieur, ce sera la même chose que si la fonction principale était un générateur. Exemple ici.
agf

50

en python normal, vous ne pouvez pas faire ce que vous voulez. il existe deux approximations proches:

def myfunction(first, second, *args):
    # args is a tuple of extra arguments

def myfunction(first, second, third=None):
    # third is optional

cependant, si vous voulez vraiment faire cela, vous pouvez certainement le faire fonctionner (au risque d'offenser les traditionalistes; o). en bref, vous écririez une wrapper(*args)fonction qui vérifie le nombre d'arguments et de délégués le cas échéant. ce genre de "hack" se fait généralement via des décorateurs. dans ce cas, vous pouvez réaliser quelque chose comme:

from typing import overload

@overload
def myfunction(first):
    ....

@myfunction.overload
def myfunction(first, second):
    ....

@myfunction.overload
def myfunction(first, second, third):
    ....

et vous implémenteriez cela en faisant le overload(first_fn) fonction (ou le constructeur) retourne un objet appelable où la __call__(*args) méthode effectue la délégation expliquée ci-dessus et la overload(another_fn) méthode ajoute des fonctions supplémentaires auxquelles peuvent être déléguées.

vous pouvez voir un exemple de quelque chose de similaire ici http://acooke.org/pytyp/pytyp.spec.dispatch.html mais qui surcharge les méthodes par type. c'est une approche très similaire ...

UPDATE: et quelque chose de similaire (en utilisant des types d'argument) est ajouté à python 3 - http://www.python.org/dev/peps/pep-0443/


L' rangeintégré utilise une surcharge, alors est-ce vraiment un hack? github.com/python/typeshed/blob/master/stdlib/2and3/…
CptJero

9

Oui c'est possible. J'ai écrit le code ci-dessous en Python 3.2.1:

def overload(*functions):
    return lambda *args, **kwargs: functions[len(args)](*args, **kwargs)

Usage:

myfunction=overload(no_arg_func, one_arg_func, two_arg_func)

Notez que le lambda retourné par les overloadfonctions choisir la fonction d'appel en fonction du nombre de sans nom arguments .

La solution n'est pas parfaite, mais pour le moment je ne peux rien écrire de mieux.


1

Pas possible directement. Vous pouvez cependant utiliser des vérifications de type explicites sur les arguments donnés, bien que cela soit généralement mal vu.

Python est dynamique. Si vous n'êtes pas sûr de ce qu'un objet peut faire, essayez simplement: et appelez une méthode dessus, sauf: erreurs.

Si vous n'avez pas besoin de surcharger en fonction des types mais uniquement du nombre d'arguments, utilisez des arguments de mot-clé.


3
Je ne pense pas qu'il connaissait les arguments optionnels.
agf

0

la surcharge des méthodes est délicate en python. Cependant, il pourrait être utile de passer les variables dict, list ou primitives.

J'ai essayé quelque chose pour mes cas d'utilisation, cela pourrait aider ici à comprendre les gens pour surcharger les méthodes.

Prenons l'exemple d'utilisation dans l'un des threads stackoverflow:

une méthode de surcharge de classe avec appel des méthodes de classe différente.

def add_bullet(sprite=None, start=None, headto=None, spead=None, acceleration=None):

passez les arguments de la classe distante:

add_bullet(sprite = 'test', start=Yes,headto={'lat':10.6666,'long':10.6666},accelaration=10.6}

OU add_bullet(sprite = 'test', start=Yes,headto={'lat':10.6666,'long':10.6666},speed=['10','20,'30']}

Ainsi, la gestion est en cours pour les variables de liste, de dictionnaire ou primitives de la surcharge de méthode.

essayez-le pour vos codes

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.