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?
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.
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.
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