Slik bruker du *args og **kwargs i Python

Lær *args og **kwargs i Python. Send et vilkårlig antall argumenter til funksjoner.

Du har en funksjon som legger sammen to tall. Fungerer fint. Men hva når du trenger å legge sammen tre? Eller ti? Du kan ikke lage en ny funksjon for hvert antall. Med *args og **kwargs i Python slipper du å bestemme antall parametere på forhånd. Funksjonen tar imot så mange verdier du sender inn.

Slik fungerer *args i Python

Stjerna foran parameternavnet gjør at Python samler alle posisjonsargumenter i en tuple:

def summer(*tall):
    resultat = 0
    for t in tall:
        resultat += t
    return resultat

print(summer(1, 2, 3))         # 6
print(summer(5, 10, 15, 20, 25)) # 75

Navnet "args" er bare en konvensjon. Skriv gjerne *tall, *verdier, eller hva som helst. Det er stjerna som gir funksjonaliteten. Python pakker alle verdiene du sender inn i en tuple, og du kan iterere over den med en for-løkke, akkurat som over en vanlig liste.

Sender du ingen argumenter, blir tupelen tom. Funksjonen krasjer ikke, men du får 0 tilbake fra eksempelet over. Det er god oppførsel.

Forskjellen fra en liste som parameter

Et alternativ er å sende inn en liste:

def summer_liste(tall_liste):
    return sum(tall_liste)

summer_liste([1, 2, 3])  # Må pakke inn i en liste

Med *args slipper du hakeparentesene:

summer(1, 2, 3)  # Sender tallene direkte

Forskjellen er brukervennlighet. *args gir et renere kall, spesielt når du ikke allerede har verdiene i en liste. Har du en eksisterende liste, kan du pakke den ut med stjerne: summer(*min_liste).

Slik fungerer **kwargs

Dobbel stjerne samler nøkkelordargumenter i en dictionary:

def vis_info(**info):
    for nokkel, verdi in info.items():
        print(f"{nokkel}: {verdi}")

vis_info(navn="Anna", alder=30, by="Oslo")

Resultatet blir:

navn: Anna
alder: 30
by: Oslo

Igjen er "kwargs" bare en konvensjon. Du kan kalle parameteren **data eller **innstillinger. Det er dobbelt-stjerna som gjør at Python samler nøkkelord-verdi-parene i en dictionary.

**kwargs er spesielt nyttig når du bygger funksjoner som tar imot innstillinger. I stedet for å definere ti valgfrie parametere med standardverdier, lar du brukeren sende inn kun det de trenger. Alt annet ignoreres eller får en standard.

Kombiner vanlige parametere med *args og **kwargs

Alle tre typene kan kombineres, men rekkefølgen er fast:

def bestilling(kunde, *produkter, **detaljer):
    print(f"Kunde: {kunde}")
    print(f"Produkter: {produkter}")
    print(f"Detaljer: {detaljer}")

bestilling("Erik", "Laptop", "Mus", frakt="Express", rabatt=10)

Resultatet:

Kunde: Erik
Produkter: ('Laptop', 'Mus')
Detaljer: {'frakt': 'Express', 'rabatt': 10}

Rekkefølgen er alltid: vanlige parametere, deretter *args, deretter **kwargs. Bytter du om, gir Python en SyntaxError. Denne rekkefølgen er logisk: først de obligatoriske verdiene, så de ekstra posisjonelle, og til slutt de navngitte tilleggsverdiene.

Pakk ut med stjerner

Utpakking med * og ** fungerer også den andre veien. Har du en liste eller dictionary, kan du pakke dem ut som argumenter til en funksjon:

def hils(fornavn, etternavn, alder):
    print(f"Hei, {fornavn} {etternavn}. Du er {alder} år.")

person = {"fornavn": "Kari", "etternavn": "Hansen", "alder": 28}
hils(**person)  # Hei, Kari Hansen. Du er 28 år.

Nøklene i dictionaryen må matche parameternavnene i funksjonen. Mangler en nøkkel, får du en TypeError. Har du en ekstra nøkkel som ikke matcher, får du også en TypeError. Det gir deg trygghet: Python sjekker at alt stemmer.

For lister bruker du én stjerne:

tall = [10, 20, 30]
print(*tall)  # 10 20 30 (tre separate argumenter)

Praktisk bruk av args og kwargs

Den vanligste bruken er i dekoratorer og wrapper-funksjoner, der du ikke vet hvilke argumenter den indre funksjonen tar:

def logg_kall(funksjon):
    def wrapper(*args, **kwargs):
        print(f"Kaller {funksjon.__name__}")
        return funksjon(*args, **kwargs)
    return wrapper

Wrapper-funksjonen videreformidler alle argumenter til den opprinnelige funksjonen uten å vite hva de er. Denne teknikken brukes i de fleste Python-rammeverk. Du trenger ikke forstå dekoratorer i detalj ennå, men det er nyttig å gjenkjenne mønsteret når du ser det i andres kode.

En annen vanlig bruk er funksjoner som bygger konfigurasjoner. Du sender inn kun de feltene du vil overstyre, og resten beholder standardverdier:

def opprett_bruker(navn, **ekstra):
    bruker = {"navn": navn, "rolle": "bruker"}
    bruker.update(ekstra)
    return bruker

print(opprett_bruker("Anna", rolle="admin", avdeling="IT"))

Tre feil å unngå med args og kwargs

Feil rekkefølge i parameterlisten. Skriver du def f(**kwargs, *args), får du en SyntaxError. *args må alltid komme før **kwargs.

Bruker *args når du trenger navngitte verdier. Hvis rekkefølgen på verdiene betyr noe (som bredde og høyde), er vanlige parametere tryggere enn *args. Navngitte parametere dokumenterer seg selv.

Fanger alt med **kwargs uten validering. Når du aksepterer hva som helst, risikerer du skrivefeil i nøkkelnavnene som aldri blir oppdaget. Legg inn sjekker for forventede nøkler når det er viktig.

En enkel validering kan se slik ut:

def innstillinger(**kwargs):
    gyldige = {"farge", "storrelse", "skrift"}
    for nokkel in kwargs:
        if nokkel not in gyldige:
            raise TypeError(f"Ukjent innstilling: {nokkel}")

Med denne sjekken oppdager du skrivefeil umiddelbart i stedet for å lure på hvorfor innstillingen ikke tok effekt.

Neste steg

Nå som du kan bruke *args og **kwargs i Python, har du full fleksibilitet i funksjonsdesign. Vil du skrive korte, anonyme funksjoner, viser lambda-funksjoner deg hvordan. Trenger du å håndtere feil i funksjonene dine, er try og except det riktige verktøyet. Du finner også flere eksempler på avansert funksjonsbruk i Python-dokumentasjonen.

Denne videoen er hentet fra kurset Python for nybegynnere på Utdannet.no. I det fulle kurset lærer du også datastrukturer, objektorientert programmering og hvordan du strukturerer større prosjekter.