Funktionen überladen mit Python
Python unterstützt kein function overloading, aber dafür keyword arguments. Dies ist eigentlich kein Nachteil, dennoch gibt es Fälle, in denen nur bestimmte Kombinationen von Übergabeparametern erlaubt sein dürfen. In diesem Beitrag geht es um eine allgemeine Lösung des Problems.
Sehr komfortabel bei Python ist die Möglichkeit, Funktionsparametern einen Standardwert zuzuweisen, der verwendet wird, wenn im Funktionsaufruf eben dieser Parameter nicht angegeben wird (keyword arguments).
print 'hello', name
>> print_name('Alice')
hello Alice
>> print_name()
hello stranger
Dies macht viele Dinge sehr einfach. In anderen Sprachen, die dies nicht unterstützen, wäre dies entweder nur mit zusätzlichen If-Abfragen möglich oder aber mit Overloading, also dem (doppelten) Implementieren einer Funktion für verschiedene Parameter.
System.out.println('hello stranger')
}
public void print_name(String name) {
System.out.println('hello ' + name)
}
Hier habe ich die Syntax absichtlich in eine andere Sprache gewechselt, denn genau das geht mit Python nicht - generell scheinen sich Programmiersprachenentwickler zwischen Standardwerten für Parameter und Overloading zu entscheiden. Zum Glück hat Python bei der Entscheidung alles richtig gemacht, dennoch vermisse ich manchmal das klassische Overloading, denn:
Bei keyword arguments gibt es ohne Weiteres keine Möglichkeit, nur bestimmte Kombinationen von Parametern zu erlauben - alle keywoard arguments sind optional. Manchmal (ich gebe zu, selten) kann es jedoch wünschenswert sein, wie in dem folgenden Beispiel entweder die Parameter host und port, oder den parameter socket, aber nicht etwa nur host oder nur port zu erlauben.
Hierfür bräuchte man in Python nun ein paar If-Abfragen; ich habe mir für diesen Fall aber lieber einen Decorator geschrieben, mit dem man die erlaubten Parameter genau spezifizieren kann und der bei einem Verstoß den Funktionsaufruf mit einem Fehler terminiert.
('host', 'port'),
))
def get_connection(socket, host, port):
pass
Bei einem Aufruf von get_connection wird zuerst überprüft, ob die übergebenen Parameter "ausreichen", um eine der spezifizierten Patterns zu erfüllen. Nur wenn dies der Fall ist, wird die Funktion weiter ausgeführt. Es ist zu beachten, dass ein Parameter auch dann als "der Funktion übergeben" angesehen wird, wenn er einen Standardwert hat und im Funktionsaufruf selbst nicht angegeben wurde.
Außerdem habe ich mich dazu entschieden, den Aufruf nicht abzubrechen, wenn ein Parameter zu viel angegeben wurde, es wird stattdessen einfach das erste Pattern verwendet, das passt.
Da nun aber die eigene Funktion auch wissen muss, welche Kombination von Parametern also verwendet werden soll, kann man ihr den Parameter "_argument_pattern" übergeben. Diesem wird dann die Nummer des Patterns übergeben.
('host', 'port'),
))
def get_connection(socket, host, port, _argument_pattern):
if _argument_pattern == 0:
print "Use socket:", socket
else:
print "Connect to:", host+':'+str(port)
>> get_connection(socket=object())
Use socket: <object object at 0xb78b8488>
>> get_connection(host='www.mindrobots.de', port='80')
Connect to: www.mindrobots.de:80
>> get_connection(host='www.mindrobots.de')
ValueError: No argument pattern matched the given arguments.
Es ist auch möglich, ein Pattern nur dann als gültig anzusehen, wenn bestimmte Werte übergeben wurden:
patterns=(('socket',),
('host', {'port': 80}),
))
def get_connection( ...
Falls also jemand mal auf dasselbe Problem stößt wie ich, kann er oder sie gerne einmal meine Lösung ausprobieren.
Es sind 1 Dateien vorhanden.
- Kommentar schreiben