Gebruik van *args en **kwargs

Ik heb dus moeite met het concept van *args en **kwargs.

Tot nu toe heb ik geleerd dat:

  • *args = lijst van argumenten - als positionele argumenten
  • **kwargs = woordenboek - waarvan de sleutels afzonderlijke trefwoord-argumenten worden en de waarden worden waarden van deze argumenten.

Ik begrijp niet voor welke programmeertaak dit nuttig zou zijn.

Misschien:

Ik denk om lijsten en woordenboeken als argumenten van een functie in te voeren EN tegelijk als jokerteken, zodat ik ELK argument kan doorgeven?

Is er een eenvoudig voorbeeld om uit te leggen hoe *args en **kwargs worden gebruikt?

Ook de tutorial die ik vond gebruikte alleen de "*" en een variabele naam.

Zijn *args en **kwargs slechts placeholders of gebruik je precies *args en **kwargs in de code?

Oplossing

De syntaxis is de * en **. De namen *args en **kwargs zijn alleen bij conventie, maar er is geen harde eis om ze te gebruiken.

Je zou *args gebruiken als je'niet zeker weet hoeveel argumenten aan je functie kunnen worden doorgegeven, m.a.w. het staat je toe een willekeurig aantal argumenten aan je functie door te geven. Bijvoorbeeld:

>>> def print_everything(*args):
        for count, thing in enumerate(args):
...         print( '{0}. {1}'.format(count, thing))
...
>>> print_everything('apple', 'banana', 'cabbage')
0. apple
1. banana
2. cabbage

Op dezelfde manier kun je met **kwargs omgaan met argumenten die je niet van te voren hebt gedefinieerd:

>>> def table_things(**kwargs):
...     for name, value in kwargs.items():
...         print( '{0} = {1}'.format(name, value))
...
>>> table_things(apple = 'fruit', cabbage = 'vegetable')
cabbage = vegetable
apple = fruit

Je kunt deze ook samen met genoemde argumenten gebruiken. De expliciete argumenten krijgen eerst hun waarde en daarna wordt al het andere doorgegeven aan *args en **kwargs. De named arguments komen eerst in de lijst. Bijvoorbeeld:

def table_things(titlestring, **kwargs)

Je kunt ook beide in dezelfde functie definitie gebruiken, maar *args moet voor **kwargs komen.

Je kunt ook de * en ** syntax gebruiken bij het aanroepen van een functie. Bijvoorbeeld:

>>> def print_three_things(a, b, c):
...     print( 'a = {0}, b = {1}, c = {2}'.format(a,b,c))
...
>>> mylist = ['aardvark', 'baboon', 'cat']
>>> print_three_things(*mylist)
a = aardvark, b = baboon, c = cat

Zoals je in dit geval kunt zien, neemt het de lijst (of tupel) van items en pakt het uit. Hierdoor koppelt hij ze aan de argumenten in de functie. Natuurlijk, je zou een * zowel in de functie definitie als in de functie aanroep kunnen hebben.

Commentaren (7)

Een plaats waar het gebruik van *args en **kwargs heel nuttig is, is voor subklassen.

class Foo(object):
    def __init__(self, value1, value2):
        # do something with the values
        print value1, value2

class MyFoo(Foo):
    def __init__(self, *args, **kwargs):
        # do something else, don't care about the args
        print 'myfoo'
        super(MyFoo, self).__init__(*args, **kwargs)

Op deze manier kun je het gedrag van de Foo klasse uitbreiden, zonder dat je al te veel over Foo hoeft te weten. Dit kan heel handig zijn als je programmeert voor een API die kan veranderen. MyFoo geeft gewoon alle argumenten door aan de Foo klasse.

Commentaren (8)

De namen *args en **kwargs of **kw zijn puur uit conventie. Het maakt het makkelijker voor ons om elkaars code te lezen's

Een plaats waar het handig is, is bij het gebruik van de struct module

struct.unpack() geeft een tupel terug terwijl struct.pack() een variabel aantal argumenten gebruikt. Bij het manipuleren van gegevens is het handig om een tupel te kunnen doorgeven aan struct.pack() bijv.

tuple_of_data = struct.unpack(format_str, data)
... manipulate the data
new_data = struct.pack(format_str, *tuple_of_data)

Zonder deze mogelijkheid zou je gedwongen zijn om te schrijven

new_data = struct.pack(format_str, tuple_of_data[0], tuple_of_data[1], tuple_of_data[2],...)

wat ook betekent dat als de format_str verandert en de grootte van de tupel verandert, ik terug moet gaan en die lange regel moet bewerken

Commentaren (0)