Python *args und **kwargs erklärt: Flexible Funktionen mit klaren Beispielen
Diese Sterne in Funktionssignaturen sind weniger mysteriös, als sie aussehen. Erfahren Sie, wie *args und **kwargs Argumente sammeln, wie dieselben Stars sie entpacken und wie Sie Funktionssignaturen entwerfen, die schwer zu missbrauchen sind.
*argssammelt zusätzliche Positionsargumente in einem Tupel.**kwargssammelt zusätzliche Schlüsselwortargumente in einem Wörterbuch.- Die Namen sind nur eine Konvention, da es auf
*und**ankommt. - Dasselbe gilt für das Entpacken einer Liste oder eines Wörterbuchs, wenn Sie eine Funktion aufrufen.
Früher oder später werden Sie eine Funktion wie def handler(*args, **kwargs) lesen und sich fragen, was sie akzeptiert. Python *args und **kwargs ermöglichen einer Funktion die Annahme einer flexiblen Anzahl von Argumenten. Sie unterstützen Dekoratoren, Wrapper und viele Bibliotheks-APIs.
In diesem Handbuch wird beschrieben, wie sie in beide Richtungen funktionieren, zusammen mit den neueren Methoden, mit denen Sie mit Python steuern können, wie eine Funktion aufgerufen wird. Wir haben jedes Beispiel auf Python 3.13 ausgeführt und die angezeigte Ausgabe stammt von diesem Lauf.
Was *args bewirkt
Ein mit einem Stern geschriebener Parameter sammelt alle zusätzlichen Positionsargumente in einem Tupel:
def total(*args):
print(type(args).__name__, args)
return sum(args)
print(total(1, 2, 3))
# tuple (1, 2, 3)
# 6
print(total())
# tuple ()
# 0
Ohne Argumente erhalten Sie einfach ein leeres Tupel, sodass die Funktion weiterhin funktioniert. Der Name args ist eine Konvention. *numbers würde sich genauso verhalten, und ein aussagekräftigerer Name ist oft besser.
Was **kwargs macht
Zwei Sterne sammeln alle zusätzlichen Schlüsselwortargumente in einem Wörterbuch:
def describe(**kwargs):
print(type(kwargs).__name__, kwargs)
describe(name="Asha", city="Pune")
# dict {'name': 'Asha', 'city': 'Pune'}
Da es sich um ein normales Wörterbuch handelt, können Sie es durchlaufen, mit get() nach Schlüsseln suchen und es weitergeben. Schlüssel behalten die Reihenfolge bei, in der sie übergeben wurden.
Parameterreihenfolge
Wenn Sie Arten von Parametern mischen, erfordert Python eine bestimmte Reihenfolge:
- Reguläre Positionsparameter
*argumente- Nur-Schlüsselwort-Parameter
**Kwargs
def order(item, qty=1, *extras, priority=False, **notes):
print(item, qty, extras, priority, notes)
order("pen")
# pen 1 () False {}
order("pen", 2, "gift wrap", "card", priority=True, note="leave at door")
# pen 2 ('gift wrap', 'card') True {'note': 'leave at door'}
Beachten Sie priority. Da es nach *extras kommt, kann es nur über den Namen festgelegt werden, sodass ein verirrtes Positionsargument es niemals versehentlich festlegen könnte. Das frühere Einfügen von **kwargs ist nicht zulässig, und unser Test ergab einen SyntaxError: „Argumente können nicht dem var-keyword-Argument folgen“.
Auspacken beim Anruf
Am Rufort funktionieren die gleichen Sterne umgekehrt. Ein Stern verteilt eine Liste oder ein Tupel in Positionsargumente, und zwei Sterne verteilen ein Wörterbuch in Schlüsselwortargumente:
nums = [4, 5, 6]
total(*nums) # same as total(4, 5, 6) -> 15
settings = {"name": "Ben", "city": "Delhi"}
describe(**settings) # same as describe(name="Ben", city="Delhi")
Das Entpacken funktioniert mit jeder Funktion, nicht nur mit denen, die *args und **kwargs verwenden. Das ist praktisch, wenn die Konfiguration als Wörterbuch ankommt:
def connect(host, port, timeout=5):
return f"{host}:{port} (timeout {timeout})"
connect(**{"host": "db.local", "port": 5432})
# 'db.local:5432 (timeout 5)'
connect(**{"host": "db.local", "port": 5432, "ssl": True})
# TypeError: connect() got an unexpected keyword argument 'ssl'
Dieser Fehler ist nützlich. Eine Funktion ohne **kwargs lehnt unbekannte Optionen ab, sodass ein Tippfehler in einem Einstellungsnamen lautstark fehlschlägt, anstatt stillschweigend ignoriert zu werden.
Nur-Schlüsselwort-Argumente
Eine leere * in der Signatur ohne Namen bedeutet „alles danach muss per Schlüsselwort übergeben werden“:
def make_user(name, *, admin=False):
return name, admin
make_user("Asha", admin=True)
# ('Asha', True)
make_user("Asha", True)
# TypeError: make_user() takes 1 positional argument but 2 were given
Dies ist eine großartige Möglichkeit, boolesche Flags zu schützen. Ein Aufruf wie make_user("Asha", True) zwingt die Leser dazu, zu erraten, was True bedeutet. Durch die Anforderung von admin=True ist jeder Aufruf selbsterklärend.
Nur positionelle Argumente
Seit Python 3.8 markiert ein / Parameter, die nur nach Position übergeben werden können:
def area(width, height, /):
return width * height
area(3, 4) # 12
area(width=3, height=4)
# TypeError: area() got some positional-only arguments
# passed as keyword arguments: 'width, height'
Dadurch kann eine Bibliothek diese Parameter später umbenennen, ohne den Code anderer zu beschädigen, da sich niemand auf die Namen verlassen kann. Mehrere integrierte Funktionen funktionieren auf diese Weise. Beispielsweise funktioniert len(obj=[1]) nicht.
Tipp: Das vollständige Muster ist def f(pos_only, /, normal, *, kw_only). Sie benötigen selten alle drei, aber wenn Sie wissen, was / und * bedeuten, können Sie Dokumentation und Bibliothekssignaturen besser lesen.
Dekorateure und Verpackungen
Dies ist in der Praxis der Hauptgrund, beides zusammen zu verwenden. Ein Wrapper muss oft alle Argumente akzeptieren, die die ursprüngliche Funktion annimmt, und sie unverändert weitergeben:
import functools, time
def timed(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
print(f"{func.__name__} took {time.perf_counter() - start:.4f}s")
return result
return wrapper
@timed
def slow_add(a, b, delay=0.01):
time.sleep(delay)
return a + b
print(slow_add(2, 3, delay=0.02))
# slow_add took 0.0205s
# 5
Der Wrapper muss die Parameter von slow_add überhaupt nicht kennen, daher funktioniert er für jede Funktion. Ihr Timing-Wert wird geringfügig abweichen. Unser Leitfaden zu Python-Dekoratoren erklärt functools.wraps und andere Details.
Optionen zum Zusammenführen
** funktioniert auch innerhalb eines Wörterbuchliterals, was eine praktische Möglichkeit bietet, Überschreibungen zusätzlich zu den Standardwerten anzuwenden:
defaults = {"theme": "light", "lang": "en"}
def build(**overrides):
return {**defaults, **overrides}
build(theme="dark")
# {'theme': 'dark', 'lang': 'en'}
Spätere Schlüssel gewinnen, daher ersetzt die Überschreibung die Standardeinstellung. Auch Unterklassen verwenden dieses Muster, wie in super().__init__(*args, **kwargs), um zusätzliche Argumente an eine übergeordnete Klasse weiterzuleiten. Weitere Informationen zu super() finden Sie unter Python-Klassen und -Objekte.
Spickzettel
| Syntax | Wo | Bedeutung |
|---|---|---|
def f(*args) |
Definition | Sammeln Sie zusätzliche Positionsargumente in einem Tupel |
def f(**kwargs) |
Definition | Sammeln Sie zusätzliche Schlüsselwortargumente in einem Diktat |
def f(a, *, b) |
Definition | b ist nur ein Schlüsselwort |
def f(a, /, b) |
Definition | a ist nur positionell |
f(*items) |
Rufen Sie an | Verteilen Sie eine Sequenz in Positionsargumente |
f(**options) |
Rufen Sie an | Verteilen Sie ein Diktat in Schlüsselwortargumente |
{**a, **b} |
Wörtlich | Wörterbücher zusammenführen |
[*a, *b] |
Wörtlich | Kombinieren Sie Iterables zu einer Liste |
Wann man sie meiden sollte
Flexibilität hat ihren Preis. Eine als def create(**kwargs) definierte Funktion sagt den Lesern nichts darüber, welche Optionen vorhanden sind, und Redakteure können sie nicht automatisch vervollständigen. Tippfehler können unbemerkt mehrere Ebenen durchlaufen, bevor etwas fehlschlägt.
Bevorzugen Sie also explizite Parameter, wenn Sie wissen, was eine Funktion benötigt. Verwenden Sie *args und **kwargs, wenn Sie wirklich Flexibilität benötigen: Wrapper, Dekoratoren, Weiterleitung von Argumenten an eine andere Funktion oder eine echte Eingabe variabler Länge wie total(*numbers). Wenn eine Funktion viele benannte Optionen benötigt, kann eine dataclass auch klarer sein.
Häufige Fehler
Verwendung eines veränderlichen Standardwerts
Hier geht es nicht um Sterne, aber er erscheint oft in deren Nähe. Ein Standardwert wird einmal erstellt, wenn die Funktion definiert wird, und dann zwischen Aufrufen geteilt:
def bad(items=[]):
items.append(1)
return items
print(bad(), bad())
# [1, 1] [1, 1]
Beide Aufrufe gaben dieselbe Liste zurück, die zu diesem Zeitpunkt zwei Elemente enthielt. Verwenden Sie items=None und erstellen Sie eine neue Liste innerhalb der Funktion.
Andere Fehler
- Vergessen auszupacken. Der Aufruf von
total(nums)übergibt eine Liste statt drei Nummern. Schreiben Sietotal(*nums). - Tippfehler werden verschluckt. Eine Funktion, die
**kwargsakzeptiert, aber unbekannte Tasten ignoriert, verbirgt falsch geschriebene Optionen. Validieren Sie sie oder vermeiden Sie**kwargs. - Das gleiche Argument zweimal übergeben.
f(1, **{"a": 2}), wobeiader erste Parameter ist, löst einen Fehler „Mehrere Werte“ aus. - Keine Weiterleitung in einem Wrapper. Beim Aufruf von
func(args, kwargs)werden ein Tupel und ein Diktat übergeben. Die korrekte Form istfunc(*args, **kwargs).
Geben Sie Hinweise für *args und **kwargs ein
Typhinweise zu *args und **kwargs beschreiben jeden einzelnen Wert, nicht die gesamte Sammlung. Das überrascht viele Menschen:
def total(*prices: float) -> float:
return sum(prices) # prices is tuple[float, ...]
def tag(**attrs: str) -> str:
return " ".join(f'{k}="{v}"' for k, v in attrs.items()) # dict[str, str]
total(1.5, 2.5) # 4.0
tag(id="x", role="button") # id="x" role="button"
Hier wird prices als Tupel von Gleitkommazahlen und attrs als Wörterbuch von Zeichenfolgen behandelt. Wenn Schlüsselwortargumente unterschiedliche Typen haben, hat Python 3.12 eine präzise Option hinzugefügt: a TypedDict kombiniert mit Unpack.
from typing import TypedDict, Unpack
class Options(TypedDict, total=False):
timeout: float
retries: int
def fetch(url: str, **opts: Unpack[Options]) -> None: ...
Ein Typprüfer wie mypy oder Pyright kann dann fetch(url, retries="3") oder einen falsch geschriebenen Optionsnamen ablehnen, was mit einem einfachen **kwargs niemals möglich ist. Das Laufzeitverhalten ändert sich jedoch nicht. Als wir fetch("u", retries="3") unter Python 3.13 ausgeführt haben, wurde es ohne Beanstandung ausgeführt, da Python selbst keine Typhinweise erzwingt.
Wenn Sie feststellen, dass Sie eine lange Liste akzeptierter Schlüssel für **kwargs dokumentieren, sollten Sie erwägen, diese durch explizite Nur-Schlüsselwort-Parameter zu ersetzen. Redakteure können sie dann automatisch vervollständigen und Fehler werden sofort erkannt.
Fazit
Denken Sie an die beiden Richtungen. In einer Definition sammeln sich Sterne. In einem Anruf packen sie aus. Fügen Sie Nur-Schlüsselwort-Argumente hinzu, um Aufrufe klarer zu gestalten, und reservieren Sie **kwargs für Code, der Argumente tatsächlich weiterleitet. Schreiben Sie zum Üben einen kleinen Dekorator, der die Argumente jedes Aufrufs protokolliert, und verwenden Sie ihn für einige verschiedene Funktionen.
Häufige Fragen
Was ist der Unterschied zwischen *args und **kwargs?
*args sammelt zusätzliche Positionsargumente in einem Tupel. **kwargs sammelt zusätzliche Schlüsselwortargumente in einem Wörterbuch. Eine Funktion kann beides zusammen verwenden.
Muss ich sie args und kwargs nennen?
Nein. Die Sterne erledigen die Arbeit, daher sind *Werte und **Optionen gleichermaßen gültig. args und kwargs sind einfach eine weithin anerkannte Konvention.
In welcher Reihenfolge sollten *args und **kwargs stehen?
Zuerst reguläre Parameter, dann *args, dann Nur-Schlüsselwort-Parameter und zuletzt **kwargs. Jede andere Reihenfolge führt zu einem SyntaxError.
Was bedeutet ein einzelnes * in einer Funktionsdefinition?
Ein bloßes * bedeutet, dass jeder Parameter danach als Schlüsselwort übergeben werden muss. Es macht Aufrufe klarer, insbesondere für boolesche Flags.
Was bedeutet / bedeutet in einer Python-Funktion?
Parameter vor / sind nur positionell, sodass Aufrufer sie nicht namentlich übergeben können. Diese Funktion wurde in Python 3.8 hinzugefügt.
Lerne weiter
Benötigen Sie Hilfe beim Testen, WordPress oder SEO?
Wir helfen Teams, bessere Software zu liefern und ihre Websites zu erweitern. Sagen Sie uns, woran Sie gerade arbeiten, und wir schlagen Ihnen einen klaren nächsten Schritt vor.
Weitere Anleitungen finden Sie unter Tests, KI und moderne Entwicklung
Hat Ihnen dieser Artikel gefallen? Wählen Sie ein Thema und springen Sie direkt in unsere neuesten Tutorials.
KI-Halluzinationen erklärt: Warum Sprachmodelle Dinge erfinden und wie man sie reduziert
KI-Halluzinationen erklärt: Was sie sind, warum Sprachmodelle sie produzieren, gängige Typen, wie man sie mit Erdung und Eingabeaufforderungen reduz…
Artikel lesen →DevOpsErklärte Umgebungsvariablen: .env-Dateien, Geheimnisse und Konfiguration richtig gemacht
Umgebungsvariablen anhand von Python-Beispielen erklärt, die wir ausgeführt haben: Sie lesen und festlegen, warum jeder Wert ein String ist, .env-Da…
Artikel lesen →SoftwareentwicklungAPI-Ratenbegrenzung erklärt: Algorithmen, Header und Behandlung von 429-Fehlern
API-Ratenbegrenzung anhand einer von uns durchgeführten Simulation erklärt: Token-Bucket, festes Fenster, gleitendes Fenster, 429 Antworten, Ratenbe…
Artikel lesen →TestautomatisierungSpott in Python: unittest.mock, Patch und die Fehler, die Tests zum Lügen machen
Mocking in Python mit unittest.mock, getestet: Mock und return_value, side_effect, Patchen, wo ein Name verwendet wird, Spezifikation und Autospec, …
Artikel lesen →SoftwaretestsCode-Abdeckung erklärt: Leitungs- und Zweigstellenabdeckung und was 100 % wirklich bedeutet
Erklärung der Codeabdeckung anhand eines echten Coverage.py-Laufs: Zeilen-, Zweig- und Bedingungsabdeckung, Lesen eines Berichts, warum bei 100 % Ab…
Artikel lesen →Datenbanken & SQLDELETE vs. TRUNCATE vs. DROP in SQL: Unterschiede, Rollback und Verwendungszweck
DELETE vs. TRUNCATE vs. DROP erklärt mit getestetem SQL: was jeweils entfernt wird, Rollback, Trigger, Identitätsrücksetzung, Geschwindigkeit und wi…
Artikel lesen →Datenbanken & SQLErklärte SQL-Ansichten: Erstellen, nutzen und vermeiden Sie Fallstricke mit Beispielen
SQL-Ansichten anhand der von uns ausgeführten Abfragen erklärt: Erstellen einer Ansicht, Live-Ergebnisse, Ausblenden von Spalten, Leistung, aktualis…
Artikel lesen →SoftwareentwicklungTypeScript-Schnittstelle vs. Typ: Echte Unterschiede, getestet mit dem Compiler
TypeScript-Schnittstelle vs. Typ, überprüft mit dem echten Compiler: Was beide können, was nur einer kann, Deklarationszusammenführung, Erweiterunge…
Artikel lesen →SoftwareentwicklungPython *args und **kwargs erklärt: Flexible Funktionen mit klaren Beispielen
Python *args und **kwargs erklärt mit Code, den wir ausgeführt haben: Packen und Entpacken, Parameterreihenfolge, Nur-Schlüsselwort- und Nur-Positio…
Artikel lesen →SoftwareentwicklungPython-Lambda-Funktionen: Syntax, tatsächliche Verwendung und wann man sie nicht verwendet
Python-Lambda-Funktionen erklärt mit Code, den wir ausgeführt haben: Syntax, Sortierung mit Schlüssel, Karte und Filter, Abschlüsse, die Late-Bindin…
Artikel lesen →Künstliche IntelligenzWas sind KI-Agenten? Wie sie funktionieren, mit einer einfachen Agentenschleife, die Sie ausführen können
Was sind KI-Agenten? Eine einfache Anleitung zur Agentenschleife, zu Tools, Speicher und Leitplanken, mit einer kleinen Python-Schleife, die wir aus…
Artikel lesen →DevOpsÜberwachung vs. Beobachtbarkeit: Der wahre Unterschied, mit Protokollen, Metriken und Traces
Überwachung vs. Beobachtbarkeit erklärt: bekannte und unbekannte Fehler, Protokolle, Metriken und Spuren, eine exemplarische Vorgehensweise für Chec…
Artikel lesen →DevOpsDocker-Volumes vs. Bind Mounts: Containerdaten auf die richtige Art und Weise beibehalten
Docker-Volumes vs. Bind-Mounts erklärt: Warum Containerdaten verschwinden, benannte Volumes, Bind-Mounts, tmpfs, Compose-Beispiele, Backups, Berecht…
Artikel lesen →TestautomatisierungTDD vs. BDD: Hauptunterschiede, eine Funktion, die auf beide Arten entwickelt wurde und wann sie jeweils verwendet werden sollte
TDD vs. BDD erklärt mit einer Rabattfunktion, die in beide Richtungen aufgebaut ist: Rot-Grün-Refaktor mit Code, den wir ausgeführt haben, Gegeben-W…
Artikel lesen →SoftwareentwicklungGit merge vs rebase: Unterschiede, Beispiele und wann man was nutzt
Git merge vs rebase erklärt mit echter Log-Ausgabe, einer Vergleichstabelle, der goldenen Regel des Rebase und einem sicheren Team-Workflow.
Artikel lesen →SoftwareentwicklungPython List Comprehension: Syntax, Beispiele und wann man darauf verzichtet
Python List Comprehension erklärt: Syntax, Filter, if-else, verschachtelte Schleifen, gemessene Zeiten und Fälle, in denen eine normale for-Schleife…
Artikel lesen →Datenbanken & SQLSQL Joins erklärt mit Beispielen (Inner, Left, Right, Full)
SQL Joins Schritt für Schritt mit Beispieltabellen und Abfragen verstehen: INNER, LEFT, RIGHT, FULL, CROSS und SELF, plus typische Fehler und Perfor…
Artikel lesen →