Python-Kurs / Positionsargumente, Schlüsselwortargumente und Standardwerte verwenden
Funktionsargumente lassen sich nach Position oder Parameternamen übergeben; Standardwerte machen ausgewählte Eingaben optional. Ein veränderliches Standardobjekt wird jedoch nicht bei jedem Aufruf neu erzeugt: Verwenden Sie bei unabhängigem Aufrufzustand beispielsweise None und erzeugen Sie die benötigte Liste im Körper.
Aufrufe nach Position und Namen lesen
Positionsargumente werden der Reihenfolge nach zugeordnet, Schlüsselwortargumente nach ihrem Namen. In format_expense("lunch", 8000) erhält name den ersten und amount den zweiten Wert. Beim Aufruf mit amount=9000, name="dinner" ist die Reihenfolge der beiden genannten Argumente dagegen nicht entscheidend.
Ein Parameter darf nicht gleichzeitig über Position und Namen zwei Werte erhalten. Ein unbekannter Schlüsselwortname ist ebenfalls ein Fehler, wenn die Funktion ihn nicht ausdrücklich zulässt. Ein gewöhnliches Positionsargument darf im Aufruf nicht auf ein Schlüsselwortargument folgen. Kontrollieren Sie bei einem Fehler sowohl die Definition als auch die konkrete Schreibweise des Aufrufs.
Das alleinstehende Sternchen in def format_expense(name, amount, *, currency="KRW"): macht die folgenden Parameter zu Schlüsselwortparametern. currency darf deshalb nur mit Namen übergeben werden. Wird es weggelassen, verwendet die Funktion den Standardwert "KRW". Die Einführung zu Schlüsselwortargumenten und die Erklärung zu Schlüsselwortparametern beschreiben diese Schnittstellen.
Optionale Einheit und eine frische Namensliste verwenden
Speichern Sie dieses vollständige Beispiel als arguments.py in UTF-8. Führen Sie python arguments.py im ausgewählten Projektinterpreter aus. Außerhalb einer aktivierten Umgebung kann unter macOS oder Ubuntu python3 der passende Name sein. Es sind keine Zusatzpakete und keine Eingabedateien nötig.
def format_expense(name, amount, *, currency="KRW"):
return f"{name}: {amount:,} {currency}"
def append_name(name, names=None):
if names is None:
names = []
names.append(name)
return names
print(format_expense("lunch", 8000))
print(format_expense(amount=9000, name="dinner", currency="KRW"))
print(append_name("A"))
print(append_name("B"))
Erwartete Ausgabe:
lunch: 8,000 KRW
dinner: 9,000 KRW
['A']
['B']
Die Einheit wird nur als Text an die formatierte Zahl angefügt. Der Code rechnet keine Währung um und prüft keine Währungskennungen. Die Kommas in 8,000 und 9,000 entstehen durch die Formatangabe :,; das ist keine automatisch an deutsche Schreibregeln angepasste Zahlendarstellung. Die Werte und die Einheit KRW bleiben im Übungscode unverändert.
append_name bekommt bei ausgelassenem zweiten Argument None. Nur dann erstellt die Funktion eine neue leere Liste und fügt den Namen hinzu. Deshalb enthält die erste ausgegebene Liste nur A, die zweite nur B. Das Ergebnis wird wie in der Übung zu Funktionen und return ausdrücklich zurückgegeben.
Gemeinsame und frische Standardobjekte vergleichen
Ein Standardausdruck wird beim Ausführen der Funktionsdefinition ausgewertet. Bei names=[] entsteht dabei eine Liste, die später von Aufrufen ohne dieses Argument wiederverwendet wird. Um den Unterschied zu sehen, speichern Sie das folgende vollständige Beispiel als defaults.py im selben Übungsordner und starten Sie python defaults.py.
def shared(name, names=[]):
names.append(name)
return names
def fresh(name, names=None):
if names is None:
names = []
names.append(name)
return names
print(shared("A"))
print(shared("B"))
print(fresh("A"))
print(fresh("B"))
Erwartete Ausgabe bei einem frischen Skriptstart:
['A']
['A', 'B']
['A']
['B']
Die beiden Aufrufe von shared verändern dasselbe Standardobjekt. Daher sieht der zweite Aufruf bereits A und ergänzt B. fresh erstellt bei jedem ausgelassenen Listenargument im Funktionskörper eine eigene Liste. Auch ein dritter Aufruf von shared würde die bestehende Sammlung weiterverwenden; der Zustand endet nicht automatisch zwischen zwei Aufrufen.
Dies betrifft nicht nur Listen. Auch eine direkt im Standardwert berechnete aktuelle Zeit wird bei der Definition bestimmt und nicht bei jedem späteren Aufruf aktualisiert. Wenn jeder Aufruf einen neuen Wert benötigt, berechnen Sie ihn im Körper. Die Dokumentation zu Standardwerten erklärt den Auswertungszeitpunkt.
Schnittstelle und Änderung übergebener Objekte prüfen
- Ergänzen Sie in
arguments.pytestweiseformat_expense("lunch", 8000, "KRW"). Der dritte Positionswert verletzt die Schlüsselwortregel und führt zuTypeError. Verwenden Sie stattdessencurrency="KRW". - Rufen Sie
format_expense("lunch", name="dinner", amount=8000)auf. Auch das führt zuTypeError, weilnamebereits durch den ersten Positionswert belegt ist. Entfernen Sie die doppelte Übergabe. - Erzeugen Sie vor einem weiteren Aufruf
names = []und speichern Sieresult = append_name("A", names). Danach enthalten sowohlnamesals auchresultA;result is namesist wahr. Die Funktion verändert hier bewusst das übergebene Objekt. - Ersetzen Sie nur in dieser Variante die Prüfung
names is Nonedurchnot names. Eine ausdrücklich übergebene leere Liste wird nun durch eine neue Liste ersetzt: Der Aufrufer behält seine leere Liste, während das Ergebnis A enthält. Stellen Sie die ursprüngliche Prüfung wieder her.
Ein leeres Objekt ist also nicht dasselbe wie ein ausgelassenes Argument. is None unterscheidet hier beide Fälle. Das verhindert den gemeinsamen Standardzustand, verhindert aber nicht die beabsichtigte Änderung einer ausdrücklich übergebenen Liste. Legen Sie im Funktionsvertrag fest, ob ein vorhandenes Objekt verändert oder zuerst kopiert werden soll. Wenn auch None selbst ein sinnvoller übergebener Wert sein muss, ist stattdessen eine eigene eindeutige Markierung für „nicht angegeben“ erforderlich.




