Python *args en **kwargs uitgelegd: Flexibele functies met duidelijke voorbeelden
Die sterren in functiesignaturen zijn minder mysterieus dan ze lijken. Leer hoe *args en **kwargs argumenten verzamelen, hoe dezelfde sterren ze uitpakken en hoe u functiesignaturen ontwerpt die moeilijk te misbruiken zijn.
*argsverzamelt extra positionele argumenten in een tupel.**kwargsverzamelt extra trefwoordargumenten in een woordenboek.- De namen zijn slechts een conventie, aangezien de
*en**er toe doen. - Dezelfde sterren pakken een lijst of woordenboek uit wanneer je een functie aanroept.
Vroeg of laat zul je een functie als def handler(*args, **kwargs) lezen en je afvragen wat deze accepteert. Python *args en **kwargs zorgen ervoor dat een functie een flexibel aantal argumenten kan aannemen. Ze voeden decorateurs, wrappers en vele bibliotheek-API’s.
In deze handleiding wordt beschreven hoe ze in beide richtingen werken, samen met de nieuwere manieren waarop je met Python kunt bepalen hoe een functie wordt aangeroepen. We hebben elk voorbeeld uitgevoerd op Python 3.13 en de getoonde uitvoer is afkomstig van die run.
Wat *args doet
Een parameter geschreven met één ster verzamelt eventuele extra positionele argumenten in een 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
Zonder argumenten krijg je eenvoudigweg een leeg tupel, zodat de functie nog steeds werkt. De naam args is een conventie. *numbers zou zich hetzelfde gedragen, en een meer beschrijvende naam is vaak beter.
Wat **kwargs doet
Twee sterren verzamelen eventuele extra trefwoordargumenten in een woordenboek:
def describe(**kwargs):
print(type(kwargs).__name__, kwargs)
describe(name="Asha", city="Pune")
# dict {'name': 'Asha', 'city': 'Pune'}
Omdat het een normaal woordenboek is, kun je er doorheen lopen, sleutels opzoeken met get() en doorgeven. Sleutels behouden de volgorde waarin ze zijn doorgegeven.
Parametervolgorde
Wanneer je verschillende soorten parameters combineert, heeft Python een specifieke volgorde nodig:
- Reguliere positionele parameters
*argumenten- Parameters voor alleen zoekwoorden
** 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'}
Let op priority. Omdat het na *extras komt, kan het alleen op naam worden ingesteld, dus een verdwaald positioneel argument kan het nooit per ongeluk instellen. Het is niet toegestaan om **kwargs eerder te plaatsen, en onze test leverde een SyntaxError op: “argumenten kunnen het var-keyword-argument niet volgen”.
Uitpakken tijdens het bellen
Dezelfde sterren werken omgekeerd op de call-site. Eén ster verspreidt een lijst of tupel in positionele argumenten, en twee sterren spreiden een woordenboek uit in trefwoordargumenten:
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")
Uitpakken werkt met elke functie, niet alleen degene die *args en **kwargs gebruiken. Dat is handig als de configuratie als woordenboek arriveert:
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'
Die fout is nuttig. Een functie zonder **kwargs wijst onbekende opties af, dus een typefout in de naam van een instelling mislukt luid in plaats van stil te worden genegeerd.
Argumenten met alleen trefwoorden
Een kale * in de handtekening, zonder naam, betekent “alles hierna moet per trefwoord worden doorgegeven”:
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
Dit is een geweldige manier om Booleaanse vlaggen te beschermen. Een oproep als make_user("Asha", True) dwingt lezers om te raden wat True betekent. Door admin=True te vereisen, spreekt elk gesprek voor zich.
Alleen positionele argumenten
Sinds Python 3.8 markeert een / parameters die alleen per positie kunnen worden doorgegeven:
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'
Hierdoor kan een bibliotheek deze parameters later hernoemen zonder iemands code te breken, aangezien niemand op de namen kan vertrouwen. Verschillende ingebouwde programma’s werken op deze manier. len(obj=[1]) werkt bijvoorbeeld niet.
Tip: Het volledige patroon is def f(pos_only, /, normal, *, kw_only). Je hebt ze zelden alle drie nodig, maar als je weet wat / en * betekenen, kun je documentatie en bibliotheekhandtekeningen lezen.
Decorateurs en inpakkers
Dit is de belangrijkste reden in de echte wereld om beide samen te gebruiken. Een wrapper moet vaak alle argumenten accepteren die de oorspronkelijke functie aanneemt, en deze onveranderd doorgeven:
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
De wrapper hoeft de parameters van slow_add helemaal niet te kennen, dus hij werkt voor elke functie. Uw timingcijfer zal enigszins afwijken. In onze gids voor Python-decorateurs worden functools.wraps en andere details uitgelegd.
Opties samenvoegen
** werkt ook binnen een letterlijk woordenboek, wat een handige manier biedt om overschrijvingen toe te passen bovenop de standaardwaarden:
defaults = {"theme": "light", "lang": "en"}
def build(**overrides):
return {**defaults, **overrides}
build(theme="dark")
# {'theme': 'dark', 'lang': 'en'}
Latere sleutels winnen, dus de overschrijving vervangt de standaardsleutel. Subklassen gebruiken dit patroon ook, zoals in super().__init__(*args, **kwargs), om extra argumenten door te geven aan een ouderklasse. Zie Python-klassen en -objecten voor meer informatie over super().
Spiekbriefje
| Syntaxis | Waar | Betekenis |
|---|---|---|
def f(*args) |
Definitie | Verzamel extra positionele argumenten in een tupel |
def f(** kwargs) |
Definitie | Verzamel extra trefwoordargumenten in een dictaat |
def f(a, *, b) |
Definitie | b is alleen voor zoekwoorden |
def f(a, /, b) |
Definitie | a is alleen positioneel |
f(*items) |
Bel | Verdeel een reeks in positionele argumenten |
f(**options) |
Bel | Verdeel een dictaat in trefwoordargumenten |
{**a, **b} |
Letterlijk | Woordenboeken samenvoegen |
[*a, *b] |
Letterlijk | Combineer iterabelen in een lijst |
Wanneer moet u ze vermijden?
Flexibiliteit heeft een prijs. Een functie gedefinieerd als def create(**kwargs) vertelt lezers niets over welke opties er zijn, en editors kunnen deze niet automatisch aanvullen. Typefouten kunnen geruisloos door verschillende lagen gaan voordat er iets misgaat.
Geef dus de voorkeur aan expliciete parameters als je weet wat een functie nodig heeft. Gebruik *args en **kwargs als je echt flexibiliteit nodig hebt: wrappers, decorateurs, argumenten doorsturen naar een andere functie, of een echte invoer met variabele lengte zoals total(*numbers). Als een functie veel benoemde opties nodig heeft, kan een dataclass ook duidelijker zijn.
Veel voorkomende fouten
Een veranderlijke standaard gebruiken
Dit gaat niet over sterren, maar het verschijnt vaak dichtbij hen. Er wordt één keer een standaardwaarde gemaakt wanneer de functie wordt gedefinieerd, en vervolgens gedeeld tussen aanroepen:
def bad(items=[]):
items.append(1)
return items
print(bad(), bad())
# [1, 1] [1, 1]
Beide oproepen leverden precies dezelfde lijst op, die tegen die tijd twee items bevatte. Gebruik items=None en maak een nieuwe lijst binnen de functie.
Andere fouten
- Vergeten uit te pakken. Als u
total(nums)belt, wordt er één lijst doorgegeven in plaats van drie nummers. Schrijftotal(*nums). - Typefouten inslikken. Een functie die
**kwargsaccepteert maar onbekende sleutels negeert, verbergt verkeerd gespelde opties. Valideer ze, of vermijd**kwargs. - Als hetzelfde argument twee keer wordt doorgegeven.
f(1, **{"a": 2}), waarbijade eerste parameter is, ontstaat er een fout met ‘meerdere waarden’. - Niet doorsturen in een wrapper. Bij het aanroepen van
func(args, kwargs)wordt een tuple en een dictaat doorgegeven. De juiste vorm isfunc(*args, **kwargs).
Typ hints voor *args en **kwargs
Typehints op *args en **kwargs beschrijven elke individuele waarde, niet de hele verzameling. Dit verbaast veel mensen:
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 wordt prices behandeld als een tupel van drijvers en attrs als een woordenboek van strings. Wanneer trefwoordargumenten verschillende typen hebben, heeft Python 3.12 een precieze optie toegevoegd: a TypedDict gecombineerd met Unpack.
from typing import TypedDict, Unpack
class Options(TypedDict, total=False):
timeout: float
retries: int
def fetch(url: str, **opts: Unpack[Options]) -> None: ...
Een typecontrole zoals mypy of Pyright kan vervolgens fetch(url, retries="3") of een verkeerd gespelde optienaam weigeren, wat een gewone **kwargs nooit kan doen. Het runtime-gedrag verandert echter niet. Toen we fetch("u", retries="3") uitvoerden onder Python 3.13, werd het zonder klachten uitgevoerd, omdat Python zelf geen typehints afdwingt.
Als je merkt dat je een lange lijst met geaccepteerde sleutels voor **kwargs documenteert, overweeg dan om deze te vervangen door expliciete parameters die alleen uit trefwoorden bestaan. Editors kunnen ze vervolgens automatisch aanvullen en fouten worden onmiddellijk opgemerkt.
Tot slot
Onthoud de twee richtingen. In een definitie verzamelen sterren zich. Tijdens een gesprek pakken ze uit. Voeg alleen-trefwoord-argumenten toe om aanroepen duidelijker te maken, en reserveer **kwargs voor code die argumenten daadwerkelijk doorstuurt. Om te oefenen kunt u een kleine decorateur schrijven die de argumenten van elke oproep registreert, en deze voor een paar verschillende functies gebruiken.
Veelgestelde vragen
Wat is het verschil tussen *args en **kwargs?
*args verzamelt extra positionele argumenten in een tuple. **kwargs verzamelt extra trefwoordargumenten in een woordenboek. Een functie kan beide samen gebruiken.
Moet ik ze args en kwargs noemen?
Nee. De sterren doen het werk, dus *waarden of **opties zijn even geldig. args en kwargs zijn eenvoudigweg een algemeen erkende conventie.
In welke volgorde moeten *args en **kwargs staan?
Eerst de reguliere parameters, daarna *args, dan de parameters voor alleen trefwoorden, en **kwargs als laatste. Elke andere volgorde veroorzaakt een SyntaxError.
Wat betekent een enkele * in een functiedefinitie?
Een kale * betekent dat elke parameter erna per trefwoord moet worden doorgegeven. Het maakt oproepen duidelijker, vooral voor Booleaanse vlaggen.
Wat betekent / betekent in een Python-functie?
Parameters vóór / zijn alleen positioneel, dus bellers kunnen ze niet op naam doorgeven. Deze functie is toegevoegd in Python 3.8.
Blijf leren
Hulp nodig met testen, WordPress of SEO?
We helpen teams betere software te leveren en hun sites te laten groeien. Vertel ons waar u mee bezig bent en wij stellen een duidelijke volgende stap voor.
Meer handleidingen over testen, AI en moderne ontwikkeling
Genoten van dit artikel? Kies een onderwerp en ga direct naar onze nieuwste tutorials.
AI-hallucinaties uitgelegd: waarom taalmodellen dingen verzinnen en hoe ze te verminderen
AI-hallucinaties uitgelegd: wat ze zijn, waarom taalmodellen ze produceren, veelvoorkomende typen, hoe je ze kunt verminderen met aarding en aanwijz…
Lees artikel →DevOpsOmgevingsvariabelen uitgelegd: .env-bestanden, geheimen en configuratie goed gedaan
Omgevingsvariabelen uitgelegd met Python-voorbeelden die we hebben uitgevoerd: ze lezen en instellen, waarom elke waarde een string is, .env-bestand…
Lees artikel →SoftwareontwikkelingAPI-snelheidsbeperking uitgelegd: algoritmen, headers en afhandeling van 429-fouten
API-snelheidsbeperking uitgelegd met een simulatie die we hebben uitgevoerd: token-bucket, vast venster, schuifvenster, 429 reacties, headers van sn…
Lees artikel →TestautomatiseringSpotten in Python: unittest.mock, patch en de fouten die tests doen liegen
Spotten in Python met unittest.mock, getest: Mock en return_value, side_effect, patchen waar een naam wordt gebruikt, spec en autospec, spotdatums e…
Lees artikel →SoftwaretestenCodedekking uitgelegd: lijn versus filiaaldekking en wat 100% werkelijk betekent
Codedekking uitgelegd met een echte dekking.py-run: dekking van lijnen, vertakkingen en condities, een rapport lezen, waarom 100% dekking nog steeds…
Lees artikel →Databases & SQLDELETE versus TRUNCATE versus DROP in SQL: verschillen, terugdraaien en wanneer elk te gebruiken
DELETE versus TRUNCATE versus DROP uitgelegd met geteste SQL: wat elk verwijdert, terugdraaien, triggers, identiteitsreset, snelheid en hoe PostgreS…
Lees artikel →Databases & SQLSQL-weergaven uitgelegd: creëer, gebruik en vermijd de valkuilen, met voorbeelden
SQL-weergaven uitgelegd met query's die we hebben uitgevoerd: een weergave maken, live resultaten, kolommen verbergen, prestaties, bijwerkbare en ge…
Lees artikel →SoftwareontwikkelingTypeScript-interface versus type: echte verschillen, getest met de compiler
TypeScript-interface versus type, gecontroleerd met de echte compiler: wat beide kunnen doen, wat slechts één kan doen, samenvoegen van declaraties,…
Lees artikel →SoftwareontwikkelingPython *args en **kwargs uitgelegd: flexibele functies met duidelijke voorbeelden
Python *args en **kwargs uitgelegd met code die we hebben uitgevoerd: in- en uitpakken, parametervolgorde, argumenten die alleen trefwoorden en posi…
Lees artikel →SoftwareontwikkelingPython Lambda-functies: syntaxis, echt gebruik en wanneer u ze niet moet gebruiken
Python lambda-functies uitgelegd met code die we hebben uitgevoerd: syntaxis, sorteren met sleutel, kaart en filter, sluitingen, de laat-bindende va…
Lees artikel →Kunstmatige intelligentieWat zijn AI-agenten? Hoe ze werken, met een eenvoudige agentloop die u kunt uitvoeren
Wat zijn AI-agenten? Een duidelijke gids voor de agentenlus, tools, geheugen en vangrails, met een kleine Python-lus die we hebben uitgevoerd, echte…
Lees artikel →DevOpsMonitoring versus waarneembaarheid: het echte verschil, met logboeken, statistieken en sporen
Monitoring versus waarneembaarheid uitgelegd: bekende en onbekende fouten, logboeken, statistieken en sporen, een walkthrough voor afrekenincidenten…
Lees artikel →DevOpsDocker-volumes versus bindingsmounts: bewaar containergegevens op de juiste manier
Docker-volumes versus bind-mounts uitgelegd: waarom containergegevens verdwijnen, benoemde volumes, bind-mounts, tmpfs, Compose-voorbeelden, back-up…
Lees artikel →TestautomatiseringTDD versus BDD: belangrijkste verschillen, één functie die op beide manieren is gebouwd en wanneer deze moet worden gebruikt
TDD versus BDD uitgelegd met één kortingsfunctie die in beide richtingen is gebouwd: rood-groen-refactor met code die we hebben uitgevoerd, gegeven-…
Lees artikel →SoftwareontwikkelingGit merge vs rebase: verschillen, voorbeelden en wanneer je wat gebruikt
Git merge vs rebase uitgelegd met echte logoutput, een vergelijkingstabel, de gouden regel van rebase en een veilige teamwerkwijze.
Lees artikel →SoftwareontwikkelingPython list comprehension: syntaxis, voorbeelden en wanneer je het vermijdt
Python list comprehension uitgelegd: syntaxis, filteren, if-else, geneste lussen, gemeten tijden en wanneer een gewone for-lus beter is.
Lees artikel →Databases & SQLSQL JOIN uitgelegd met voorbeelden (Inner, Left, Right, Full)
Begrijp SQL joins stap voor stap met voorbeeldtabellen en queries: INNER, LEFT, RIGHT, FULL, CROSS en SELF, plus veelgemaakte fouten en prestatietips.
Lees artikel →