web-dev-qa-db-fra.com

Comment utiliser la surcharge de méthodes en Python?

J'essaie d'implémenter la surcharge de méthodes en Python:

class A:
    def stackoverflow(self):    
        print 'first method'
    def stackoverflow(self, i):
        print 'second method', i

ob=A()
ob.stackoverflow(2)

mais le résultat est second method 2; De même:

class A:
    def stackoverflow(self):    
        print 'first method'
    def stackoverflow(self, i):
        print 'second method', i

ob=A()
ob.stackoverflow()

donne

Traceback (most recent call last):
  File "my.py", line 9, in <module>
    ob.stackoverflow()
TypeError: stackoverflow() takes exactly 2 arguments (1 given)

Comment puis-je faire ce travail?

143
user1335578

C'est méthode surcharger pas méthode surcharger . Et en Python, vous faites tout cela en une seule fonction:

class A:

    def stackoverflow(self, i='some_default_value'):    
        print 'only method'

ob=A()
ob.stackoverflow(2)
ob.stackoverflow()

Vous ne pouvez pas avoir deux méthodes portant le même nom dans Python - et vous n'avez pas besoin de le faire.

Voir la section Valeurs d'argument par défaut du tutoriel Python. Voir "Le moindre étonnement" et l'argument de la valeur par défaut mutable pour une erreur commune à éviter.

Edit : Voir PEP 44 pour obtenir des informations sur les nouvelles fonctions génériques de distribution uniques dans Python 3.4.

137
agf

En Python, vous ne faites pas les choses de cette façon. Quand les gens le font dans des langages comme Java, ils veulent généralement une valeur par défaut (sinon, ils veulent une méthode avec un nom différent). Donc, en Python, vous pouvez avoir des valeurs par défaut .

class A(object):  # Remember the ``object`` bit when working in Python 2.x

    def stackoverflow(self, i=None):
        if i is None:
            print 'first form'
        else:
            print 'second form'

Comme vous pouvez le constater, vous pouvez l'utiliser pour déclencher un comportement distinct plutôt que de simplement avoir une valeur par défaut.

>>> ob = A()
>>> ob.stackoverflow()
first form
>>> ob.stackoverflow(2)
second form
46
Chris Morgan

Vous pouvez également utiliser pythonlangutil :

from pythonlangutil.overload import Overload, signature

class A:
    @Overload
    @signature()
    def stackoverflow(self):    
        print 'first method'

    @stackoverflow.overload
    @signature("int")
    def stackoverflow(self, i):
        print 'second method', i
42
Ehsan Keshavarzian

Vous ne pouvez pas, ne devez jamais et ne voulez pas vraiment.

En Python, tout est un objet. Les classes sont des choses, donc ce sont des objets. Ainsi sont les méthodes.

Il existe un objet appelé A qui est une classe. Il possède un attribut appelé stackoverflow. Il ne peut avoir qu'un seul de ces attributs.

Lorsque vous écrivez def stackoverflow(...): ..., vous créez un objet qui est la méthode et vous l'affectez à l'attribut stackoverflow de A. Si vous écrivez deux définitions, la seconde remplace la première, de la même manière que l'affectation se comporte toujours.

De plus, vous ne voulez pas écrire de code qui rend fous le genre de choses pour lesquelles la surcharge est parfois utilisée. Ce n'est pas comme ça que la langue fonctionne.

Au lieu d’essayer de définir une fonction distincte pour chaque type d’objet (ce qui n’a aucun sens puisque vous ne spécifiez pas de type pour les paramètres de fonction), cessez de vous inquiéter de ce qui est - are et commence à penser à ce qu'ils peuvent faire.

Non seulement vous ne pouvez pas en écrire un distinct pour gérer un tuple ou une liste, mais aussi ne pas vouloir ou ne pas avoir besoin de.

Tout ce que vous faites est de tirer parti du fait qu’elles sont toutes les deux, par exemple, itérables (c’est-à-dire que vous pouvez écrire for element in container:). (Le fait qu'ils ne soient pas directement liés par héritage est sans importance.)

24
Karl Knechtel

J'écris ma réponse dans Python 3.2.1.

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

Comment ça fonctionne:

  1. overload prend n'importe quelle quantité de callables et les stocke dans le tuple functions, puis renvoie lambda.
  2. Le lambda prend n'importe quel nombre d'arguments, puis renvoie le résultat de la fonction d'appel stockée dans functions[number_of_unnamed_args_passed] appelé avec des arguments transmis au lambda.

Usage:

class A:
    stackoverflow=overload(                    \
        None, \ 
        #there is always a self argument, so this should never get called
        lambda self: print('First method'),      \
        lambda self, i: print('Second method', i) \
    )
16
GingerPlusPlus

J'écris ma réponse dans Python 2.7:

En Python, la surcharge de méthode n'est pas possible; si vous voulez vraiment accéder à la même fonction avec des fonctionnalités différentes, je vous suggère d’opter pour une méthode prioritaire.

class Base(): # Base class
    '''def add(self,a,b):
        s=a+b
        print s'''

    def add(self,a,b,c):
        self.a=a
        self.b=b
        self.c=c

        sum =a+b+c
        print sum

class Derived(Base): # Derived class
    def add(self,a,b): # overriding method
        sum=a+b
        print sum



add_fun_1=Base() #instance creation for Base class
add_fun_2=Derived()#instance creation for Derived class

add_fun_1.add(4,2,5) # function with 3 arguments
add_fun_2.add(4,2)   # function with 2 arguments
13
Moorthi Muthu

Je pense que le mot que vous recherchez est "surcharger". Il n'y a pas de surcharge de méthode en python. Vous pouvez cependant utiliser les arguments par défaut, comme suit.

def stackoverflow(self, i=None):
    if i != None:     
        print 'second method', i
    else:
        print 'first method'

Lorsque vous transmettez un argument, il suit la logique de la première condition et exécute la première instruction print. Lorsque vous ne lui passez aucun argument, il passe à la condition else et exécute la deuxième instruction print.

13
mayhewr

En Python, la surcharge n'est pas un concept appliqué. Cependant, si vous essayez de créer un cas où, par exemple, vous souhaitez qu'un initialiseur soit exécuté si un argument de type foo est passé et un autre initialiseur pour un argument de type bar alors, puisque tout dans Python est traité en tant qu'objet, vous pouvez vérifier le nom du type de classe de l'objet transmis et écrire un traitement conditionnel en fonction de celui-ci.

class A:
   def __init__(self, arg)
      # Get the Argument's class type as a String
      argClass = arg.__class__.__name__

      if argClass == 'foo':
         print 'Arg is of type "foo"'
         ...
      Elif argClass == 'bar':
         print 'Arg is of type "bar"'
         ...
      else
         print 'Arg is of a different type'
         ...

Ce concept peut être appliqué à plusieurs scénarios différents par le biais de différentes méthodes, selon les besoins.

9
S. Gamgee

En Python, vous le feriez avec un argument par défaut.

class A:

    def stackoverflow(self, i=None):    
        if i == None:
            print 'first method'
        else:
            print 'second method',i
7
John Gaines Jr.

Je viens de découvrir ceci https://github.com/bintoro/overloading.py pour tous ceux qui pourraient être intéressés.

À partir du readme du référentiel lié:

la surcharge est un module qui fournit une répartition des fonctions en fonction des types et du nombre d'arguments d'exécution.

Lorsqu'une fonction surchargée est appelée, le répartiteur compare les arguments fournis aux signatures de fonction disponibles et appelle l'implémentation qui fournit la correspondance la plus précise possible.

Caractéristiques

La validation des fonctions lors de l'enregistrement et les règles de résolution détaillées garantissent un résultat unique et bien défini lors de l'exécution. Implémente la mise en cache de résolution de fonction pour des performances exceptionnelles. Prend en charge les paramètres facultatifs (valeurs par défaut) dans les signatures de fonction. Evalue les arguments de position et de mot clé lors de la résolution de la meilleure correspondance. Prend en charge les fonctions de secours et l'exécution du code partagé. Prend en charge le polymorphisme d'argument. Prend en charge les classes et l'héritage, y compris les méthodes de classe et les méthodes statiques.

5
Mark Lawrence

Alors que @agf avait raison avec la réponse dans le passé avec PEP-3124 , nous avons obtenu notre suggestion de syntaxe. Voir saisie de la documentation pour plus de détails sur le décorateur @overload, mais notez qu'il ne s'agit que de la syntaxe suggérée et IMHO c'est tout ce que les gens ont discuté depuis. Personnellement, je suis d’accord pour dire que le fait d’avoir plusieurs fonctions avec des signatures différentes le rend plus lisible que d’avoir une seule fonction avec plus de 20 arguments tous définis sur une valeur par défaut (None la plupart du temps), puis de devoir bricoler sans fin avec if, Elif, elsechains pour savoir ce que l'appelant souhaite réellement que notre fonction fasse avec le jeu d'arguments fourni. Ceci, cela se fait attendre depuis longtemps après le Python Zen

Beau vaut mieux que moche.

et sans doute aussi

Simple c'est mieux que complexe.

Directement de la documentation officielle Python liée ci-dessus:

@overload
def process(response: None) -> None:
    ...
@overload
def process(response: int) -> Tuple[int, str]:
    ...
@overload
def process(response: bytes) -> str:
    ...
def process(response):
    <actual implementation>
5
masi

Python ne prend pas en charge la surcharge de méthodes comme Java ou C++. Nous pouvons surcharger les méthodes mais ne pouvons utiliser que la dernière méthode définie.

# First sum method.
# Takes two argument and print their sum
def sum(a, b):
    s = a + b
    print(s)

# Second sum method
# Takes three argument and print their sum
def sum(a, b, c):
    s = a + b + c
    print(s)

# Uncommenting the below line shows an error    
# sum(4, 5)

# This line will call the second sum method
sum(4, 5, 5)

Nous devons fournir des arguments optionnels ou * args afin de fournir un nombre différent d'arguments lors de l'appel.

Courtoisie de https://www.geeksforgeeks.org/python-method-overloading/

3
Atihska

Python 3.x inclut une bibliothèque de typage standard qui permet la surcharge de méthodes à l’aide de @overload decorator. Malheureusement, cela rend le code plus lisible, car les méthodes décorées avec @ overload devront être suivies par une méthode non décorée qui gère différents arguments. Plus peut être trouvé ici ici mais pour votre exemple:

from typing import overload
from typing import Any, Optional
class A(object):
    @overload
    def stackoverflow(self) -> None:    
        print('first method')
    @overload
    def stackoverflow(self, i: Any) -> None:
        print('second method', i)
    def stackoverflow(self, i: Optional[Any] = None) -> None:
        if not i:
            print('first method')
        else:
            print('second method', i)

ob=A()
ob.stackoverflow(2)
2
nickthefreak

Dans le fichier MathMethod.py

from multipledispatch import dispatch
@dispatch(int,int)
def Add(a,b):
   return a+b 
@dispatch(int,int,int)  
def Add(a,b,c):
   return a+b+c 
@dispatch(int,int,int,int)    
def Add(a,b,c,d):
   return a+b+c+d

Dans le fichier Main.py

import MathMethod as MM 
print(MM.Add(200,1000,1000,200))

Nous pouvons surcharger la méthode en utilisant multipledispatch

0
Mahabubuzzaman