Wie verwende ich das Überladen von Methoden in Python?

169

Ich versuche, Methodenüberladung in Python zu implementieren:

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

ob=A()
ob.stackoverflow(2)

aber die Ausgabe ist second method 2; ähnlich:

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

ob=A()
ob.stackoverflow()

gibt

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

Wie mache ich das?

user1335578
quelle
39
Stellen Sie sich in Python Methoden als eine spezielle Menge von " Attributen " vor, und es kann nur ein " Attribut " (und damit eine Methode) eines bestimmten Namens für ein Objekt geben. Die letzte Methode überschreibt alle vorherigen Methoden. In Java sind Methoden keine erstklassigen Bürger (sie sind keine "Attribute von Objekten"), sondern werden durch "Senden von Nachrichten" aufgerufen, die statisch aufgelöst werden, basierend auf dem nächstgelegenen Typ (bei dem Überladung auftritt).
6
Warum wird noch keine Antwort auf diese Frage akzeptiert? Klicken Sie einfach auf das markierte Häkchen links von Ihrer Lieblingsantwort ...
glglgl
2
Mögliches Duplikat überladener Funktionen in Python?
Ciro Santilli 14 冠状 病 六四 事件 法轮功

Antworten:

150

Es Methode Überlastung nicht Methode überschrieben . Und in Python erledigen Sie alles in einer Funktion:

class A:

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

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

Sie können in Python nicht zwei Methoden mit demselben Namen haben - und das müssen Sie auch nicht.

Weitere Informationen finden Sie im Abschnitt Standardargumentwerte des Python-Lernprogramms. Unter "Wenig Erstaunen" und dem Argument "Veränderbarer Standard" finden Sie einen häufigen Fehler, den Sie vermeiden sollten.

Bearbeiten : Informationen zu den neuen generischen Einzelversandfunktionen in Python 3.4 finden Sie in PEP 443 .

agf
quelle
119
und Sie müssen nicht - IMHO manchmal wäre es sehr praktisch, Methodenüberladung wie z. B. in C ++ zu haben. Ok, es wird nicht in dem Sinne "benötigt", dass es nicht mit anderen Konstrukten durchgeführt werden kann - aber es würde einige Dinge einfacher und einfacher machen.
Andreas Florath
7
@AndreasFlorath Ich bin anderer Meinung. Lernen Sie, das Tippen von Enten zu lieben und schreiben Sie jede Methode so, dass sie nur eines tut und keine Methodenüberladung erforderlich ist.
Agf
4
+1 dafür, dass ich über den "häufigen Fehler, den ich vermeiden sollte" gelesen habe, bevor ich erwischt wurde
mdup
43
Ich möchte ein wenig anderer Meinung sein;) ... Überladen macht Code oft sauberer, weil Sie die Methode nicht mit zu vielen if-else-Anweisungen packen, um verschiedene Fälle zu behandeln. In gewissem Sinne verwendet die gesamte Bandbreite der funktionalen Sprachen eine ähnliche Idee, dh Argument-Muster-Matching. Was bedeutet, dass Sie kleinere, sauberere Methoden haben würden, anstatt riesige, unlesbare.
Sten
2
@ user1019129 Dies ist der Zweck der generischen Funktionen für den Einzelversand, die in Python 3.4 hinzugefügt und in meiner Antwort verlinkt wurden.
Agf
61

Sie können auch Pythonlangutil verwenden :

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
Ehsan Keshavarzian
quelle
6
Ich denke, das ist die einzig gültige Antwort auf die Frage. Ich würde doppelt stimmen, wenn ich könnte.
Michael
3
Es ist gut, aber es funktioniert nicht mit Rohfunktionen, sondern nur mit Methoden innerhalb einer Klasse.
Legit Stack
1
@LegitStack Diese Funktionalität kann auch hinzugefügt werden. Es ist nicht unmöglich.
Ehsan Keshavarzian
3
@LegitStack Ich habe den Code auf GitHub aktualisiert, jetzt funktioniert er auch mit Funktionen.
Ehsan Keshavarzian
1
@PaulPrice Das stimmt. Ich habe meine Antwort aktualisiert und den offiziellen Support-Bereich entfernt. Sie können meinen Code weiterhin zum Versenden von Überladungen verwenden. Es funktioniert jetzt sowohl mit Methoden als auch mit Funktionen. Holen Sie sich den Code von GitHub. Ich habe PyPi noch nicht aktualisiert.
Ehsan Keshavarzian
48

In Python machen Sie die Dinge nicht so. Wenn Benutzer dies in Sprachen wie Java tun, möchten sie im Allgemeinen einen Standardwert (wenn nicht, möchten sie im Allgemeinen eine Methode mit einem anderen Namen). In Python können Sie also Standardwerte haben .

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'

Wie Sie sehen, können Sie dies verwenden, um ein separates Verhalten auszulösen, anstatt nur einen Standardwert zu haben.

>>> ob = A()
>>> ob.stackoverflow()
first form
>>> ob.stackoverflow(2)
second form
Chris Morgan
quelle
2
Meistens Noneist es nützlich, wenn Sie einen veränderlichen Standardwert wünschen. Separates Verhalten sollte in separaten Funktionen erfolgen.
agf
@agf: Nonekann auch als echter Standardwert nützlich sein.
Chris Morgan
Ja, aber ich bezog mich darauf, es als Sentinel-Wert zu verwenden. So verwenden Sie es in Ihrer Antwort, und ich denke, mein Kommentar macht dies deutlich.
agf
Sie sagen "allgemein"? Wollen Sie damit sagen, dass dies nicht immer so ist?
Joel
24

Sie können, müssen und wollen nicht wirklich.

In Python ist alles ein Objekt. Klassen sind Dinge, also Objekte. Methoden sind es auch.

Es gibt ein Objekt namens, Adas eine Klasse ist. Es hat ein Attribut namens stackoverflow. Es kann nur ein solches Attribut haben.

Wenn Sie schreiben def stackoverflow(...): ..., erstellen Sie ein Objekt, das die Methode ist, und weisen es dem stackoverflowAttribut von zu A. Wenn Sie zwei Definitionen schreiben, ersetzt die zweite die erste, so wie sich die Zuweisung immer verhält.

Sie möchten außerdem keinen Code schreiben, der die wilderen Dinge tut, für die Überladung manchmal verwendet wird. So funktioniert die Sprache nicht.

Anstatt zu versuchen, eine separate Funktion für jeden Typ von Dingen zu definieren, die Ihnen gegeben werden könnten (was wenig Sinn macht, da Sie ohnehin keine Typen für Funktionsparameter angeben), machen Gedanken mehr darüber, was Dinge sind, und überlegen Sie, was sie tun können .

Sie können nicht nur kein separates schreiben, um ein Tupel gegen eine Liste zu verarbeiten, sondern möchten oder müssen es auch nicht .

Alles, was Sie tun, ist die Tatsache auszunutzen, dass beide beispielsweise iterierbar sind (dh Sie können schreiben for element in container:). (Die Tatsache, dass sie nicht direkt durch Vererbung verbunden sind, ist irrelevant.)

Karl Knechtel
quelle
6
TBH, ich wäre vorsichtiger mit "nie brauchen". Dies ist etwas, das mit jedem Merkmal einer realen Welt und einer vollständigen Programmiersprache versehen werden kann und daher kein gültiges Argument ist. Wer braucht Generatoren? Wer braucht Unterricht? Programmiersprachen sind nur syntaktischer Zucker für etwas Konkreteres.
Sebastian Mach
6
Stimme überhaupt nicht zu. Es kann sein, dass Sie "nie brauchten" oder "nie wollten", aber es gibt genug Anwendungen, in denen Sie verzweifelt wollen. Versuchen Sie beispielsweise, ein Programm zu schreiben, das sowohl Python- als auch Numpy-Arrays elegant verarbeitet, ohne Ihr Programm mit Instanzen von ...
Elmar Zander
1
Basierend auf Masis Antwort würde ich sagen, dass "du kannst nicht" jetzt falsch und veraltet ist. Aufgrund der Existenz des @overloadDekorateurs würde ich sagen, dass "nicht wirklich wollen" bestenfalls fraglich ist. Aus PEP-3124 geht hervor, dass "... es derzeit ein gängiges Anti-Pattern für Python-Code ist, die Typen empfangener Argumente zu überprüfen ... der 'offensichtliche Weg', dies zu tun, ist die Typprüfung, aber dies ist spröde und verschlossen Erweiterung ... "Es scheint also, als wollten genug Leute, dass es Teil von Python wurde.
Mike S
@ MikeS, der Standard @overloadist nur für die Eingabe.
Narfanar
@Narfanar Ich weiß nicht, wie Ihre Antwort auf meinen Kommentar zutrifft. Könntest du erklären?
Mike S
16

Während @agf mit PEP-3124 in der Vergangenheit mit der Antwort Recht hatte, haben wir unseren Syntaxzucker erhalten. Weitere Informationen zum @overloadDekorateur finden Sie in der Schreibdokumentation. Beachten Sie jedoch, dass dies wirklich nur Syntaxzucker ist. IMHO ist dies alles, worüber sich die Leute seitdem gestritten haben. Persönlich stimme ich , dass mit unterschiedlichen Signaturen mehr Funktionen haben , macht es besser lesbar dann mit 20+ Argumenten alle auf einen Standardwert eine einzige Funktion ( die Nonemeiste Zeit) und dann endlos mit herumzudaddeln mit if, elif, elseKetten , um herauszufinden , was Der Aufrufer möchte tatsächlich, dass unsere Funktion mit den bereitgestellten Argumenten zu tun hat. Dies war nach dem Python Zen längst überfällig

Schön ist besser als hässlich.

und wohl auch

Einfach ist besser als komplex.

Direkt aus der oben verlinkten offiziellen Python-Dokumentation:

from typing import overload
@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>
Masi
quelle
genau das, wonach ich gesucht habe, ordentlicher als die Definition eines eigenen überladenden Dekorateurs
pcko1
2
Übrigens: Für alle, die sich fragen, warum dies nicht funktioniert, würde ich empfehlen, einen Blick auf die Diskussion unter stackoverflow.com/questions/52034771/… zu werfen - die @overloaded-Funktionen sollten keine tatsächliche Implementierung haben. Dies ist aus dem Beispiel in der Python-Dokumentation nicht ersichtlich.
Masi
15

Ich schreibe meine Antwort in Python 3.2.1.

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

Wie es funktioniert:

  1. overloadNimmt eine beliebige Anzahl von Callables, speichert sie in Tupel functionsund gibt dann Lambda zurück.
  2. Das Lambda akzeptiert eine beliebige Anzahl von Argumenten und gibt dann das Ergebnis der Aufruffunktion zurück, die in functions[number_of_unnamed_args_passed]aufgerufenen Argumenten gespeichert ist, die an das Lambda übergeben wurden.

Verwendung:

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) \
    )
GingerPlusPlus
quelle
14

Ich denke, das Wort, das Sie suchen, ist "Überladung". In Python gibt es keine Methodenüberladung. Sie können jedoch die folgenden Standardargumente verwenden.

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

Wenn Sie ein Argument übergeben, folgt es der Logik der ersten Bedingung und führt die erste print-Anweisung aus. Wenn Sie keine Argumente übergeben, geht es in die elseBedingung und führt die zweite print-Anweisung aus.

Mayhewr
quelle
13

Ich schreibe meine Antwort in Python 2.7:

In Python ist eine Methodenüberladung nicht möglich. Wenn Sie wirklich auf dieselbe Funktion mit unterschiedlichen Funktionen zugreifen möchten, empfehlen wir Ihnen, die Methode zu überschreiben.

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
Moorthi Muthu
quelle
9

In Python ist das Überladen kein angewandtes Konzept. Wenn Sie jedoch versuchen, einen Fall zu erstellen, in dem beispielsweise ein Initialisierer ausgeführt werden soll, wenn ein Argument vom Typ übergeben wird, foound ein anderer Initialisierer für ein Argument vom Typ bar, können Sie dies überprüfen, da alles in Python als Objekt behandelt wird den Namen des Klassentyps des übergebenen Objekts und die darauf basierende bedingte Schreibbehandlung.

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

Dieses Konzept kann je nach Bedarf mit verschiedenen Methoden auf mehrere verschiedene Szenarien angewendet werden.

S. Gamgee
quelle
7

In Python würden Sie dies mit einem Standardargument tun.

class A:

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

Bin gerade auf diese https://github.com/bintoro/overloading.py gestoßen gestoßen, für alle, die interessiert sein könnten.

Aus der Readme-Datei des verknüpften Repositorys:

Überladen ist ein Modul, das das Versenden von Funktionen basierend auf den Typen und der Anzahl der Laufzeitargumente bereitstellt.

Wenn eine überladene Funktion aufgerufen wird, vergleicht der Dispatcher die angegebenen Argumente mit den verfügbaren Funktionssignaturen und ruft die Implementierung auf, die die genaueste Übereinstimmung liefert.

Eigenschaften

Die Funktionsvalidierung bei der Registrierung und detaillierte Auflösungsregeln garantieren zur Laufzeit ein eindeutiges, genau definiertes Ergebnis. Implementiert das Caching der Funktionsauflösung für eine hervorragende Leistung. Unterstützt optionale Parameter (Standardwerte) in Funktionssignaturen. Wertet sowohl Positions- als auch Schlüsselwortargumente aus, wenn die beste Übereinstimmung gefunden wird. Unterstützt Fallback-Funktionen und die Ausführung von gemeinsam genutztem Code. Unterstützt Argumentpolymorphismus. Unterstützt Klassen und Vererbung, einschließlich Klassenmethoden und statischer Methoden.

Mark Lawrence
quelle
3

Python unterstützt keine Methodenüberladung wie Java oder C ++. Wir können die Methoden überladen, aber nur die zuletzt definierte Methode verwenden.

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

Wir müssen optionale Argumente oder * Argumente angeben, um beim Aufrufen eine andere Anzahl von Argumenten bereitzustellen.

Mit freundlicher Genehmigung von https://www.geeksforgeeks.org/python-method-overloading/

Atihska
quelle
Dies ist keine Überlastung. Es heißt Überschreiben. Letzteres wird von Python unterstützt. Die erste kann mit Dekorateuren implementiert werden.
Paebbels
2

Python 3.x enthält eine Standard-Typisierungsbibliothek, die das Überladen von Methoden mithilfe von @overload decorator ermöglicht. Leider dient dies dazu, den Code besser lesbar zu machen, da auf die mit @overload dekorierten Methoden eine nicht dekorierte Methode folgen muss, die verschiedene Argumente verarbeitet. Mehr finden Sie hier , aber für Ihr Beispiel:

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)
nickthefreak
quelle
1
Das "The" am Ende Ihrer Antwort lässt mich denken, dass Sie Ihre Antwort noch nicht fertig geschrieben haben. Bitte bearbeiten Sie Ihre Antwort, um sie zu vervollständigen.
Artjom B.
0

In der Datei 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

In der Datei Main.py.

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

Wir können die Methode mit Multipledispatch überladen

Mahabubuzzaman
quelle
Dies erfordert die Verwendung eines Multipledispatch-Pakets ( pypi.org/project/multipledispatch ), das nicht Teil des Python-Kerns ist.
Antony
0

Python hat den @ overload Decorator mit hinzugefügt PEP-3124 , um syntaktischen Zucker zum Überladen über die Typprüfung bereitzustellen - anstatt nur mit dem Überschreiben zu arbeiten.

Codebeispiel zum Überladen über @overload von PEP-3124

from overloading import overload
from collections import Iterable

def flatten(ob):
    """Flatten an object to its component iterables"""
    yield ob

@overload
def flatten(ob: Iterable):
    for o in ob:
        for ob in flatten(o):
            yield ob

@overload
def flatten(ob: basestring):
    yield ob

wird vom @ overload-decorator in Folgendes umgewandelt:

def flatten(ob):
    if isinstance(ob, basestring) or not isinstance(ob, Iterable):
        yield ob
    else:
        for o in ob:
            for ob in flatten(o):
                yield ob
Nex
quelle