*args- ja **kwargs-arvojen käyttö

Minulla on siis vaikeuksia käsitteiden *args ja **kwargs kanssa.

Tähän mennessä olen oppinut, että:

  • *args = argumenttiluettelo - sijaintiargumentteina.
  • **kwargs = sanakirja - jonka avaimista tulee erillisiä avainsana-argumentteja ja arvoista näiden argumenttien arvoja.

En ymmärrä, missä ohjelmointitehtävässä tästä olisi hyötyä.

Ehkäpä:

Luulen, että voin syöttää luetteloita ja sanakirjoja funktion argumentteina JA samalla jokerimerkkinä, jotta voin siirtää MIKÄ tahansa argumentin?

Onko olemassa yksinkertaista esimerkkiä, joka selittäisi, miten *args ja **kwargs käytetään?

Myös löytämässäni opetusohjelmassa käytettiin vain "*" ja muuttujan nimeä.

Ovatko *args ja **kwargs pelkkiä paikanvartijoita vai käytetäänkö koodissa juuri *args ja **kwargs?

Ratkaisu

Syntaksi on * ja **. Nimet *args ja **kwargs ovat vain konvention mukaisia, mutta niiden käyttämiseen ei ole mitään pakollista vaatimusta.

Käytät *args, kun et ole varma, kuinka monta argumenttia funktiollesi välitetään, eli sen avulla voit välittää funktiollesi mielivaltaisen määrän argumentteja. Esimerkiksi:

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

Vastaavasti **kwargs antaa sinulle mahdollisuuden käsitellä nimettyjä argumentteja, joita et ole määritellyt etukäteen:

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

Voit käyttää myös näitä yhdessä nimettyjen argumenttien kanssa. Selkeät argumentit saavat arvot ensin, ja sitten kaikki muu välitetään *args:lle ja **kwargs:lle. Nimetyt argumentit tulevat listassa ensimmäisenä. Esimerkiksi:

def table_things(titlestring, **kwargs)

Voit myös käyttää molempia samassa funktiomääritelmässä, mutta *args:n on oltava ennen **kwargs:a.

Voit myös käyttää *- ja **-syntaksia kutsuessasi funktiota. Esimerkiksi:

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

Kuten näet, tässä tapauksessa se ottaa listan (tai tuplan) kohteita ja purkaa sen. Näin se sovittaa ne funktion argumentteihin. Tietenkin * voisi olla sekä funktion määritelmässä että funktiokutsussa.

Kommentit (7)

Yksi paikka, jossa *args ja **kwargs on varsin hyödyllinen, on aliluokittelu.

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)

Näin voit laajentaa Foo-luokan käyttäytymistä ilman, että sinun tarvitsee tietää liikaa Foo-luokasta. Tämä voi olla varsin kätevää, jos ohjelmoit API:lle, joka saattaa muuttua. MyFoo vain välittää kaikki argumentit Foo-luokalle.

Kommentit (8)

Nimet *args ja **kwargs tai **kw ovat puhtaasti konvention mukaisia. Se helpottaa toistemme koodin lukemista.

Yksi paikka, jossa se on kätevä, on käytettäessä struct-moduulia.

struct.unpack() palauttaa tuplan, kun taas struct.pack() käyttää muuttuvaa määrää argumentteja. Kun dataa käsitellään, on kätevää pystyä antamaan tuple struck.pack():lle esim.

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

ilman tätä mahdollisuutta sinun olisi pakko kirjoittaa

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

mikä tarkoittaa myös sitä, että jos format_str muuttuu ja tuplen koko muuttuu, minun on palattava takaisin ja muokattava tuota todella pitkää riviä.

Kommentit (0)