Python: args i kwargs

8-lut-2021

Python jest fajny, bo jest dynamiczny. Napiszesz sobie funkcję, a potem ni z tego ni z owego można ją wywoływać na wiele sposobów. Popatrz na ten przykład:

def show_args(arg_1, arg_2):
   print(arg_1)
   print(arg_2)
 
show_args('one','two')

Proste? No pewnie, że proste! Funkcja ma dwa argumenty i wywołujemy ją z dwoma argumentami i już!

Ale może by tak, mając listę dwóch elementów przekazać ją do tej funkcji? Może funkcja będzie na tyle sprytna, żeby zrozumieć o co chodzi? Niestety będzie błąd:

show_args(['one','two'])
TypeError: show_args() missing 1 required positional argument: 'arg_2'

… ale gdyby tak, przed listą dodać gwiazdkę, to Python „wyłuska z listy jej elementy i przekaże je do funkcji:

show_args(*['one','two'])
one
two

Wow! Dobre!

No a jeśli nie mamy listy argumentów, tylko słownik? I jeśli jeszcze w tym słowniku elementy są „przypadkowo” nazwane tak, jak argumenty testowanej funkcji? Przy pierwszym podejściu – niestety klapa:

show_args({'arg_2':'two', 'arg_1':'one'})
TypeError: show_args() missing 1 required positional argument: 'arg_2'

Ale my już wiemy, jak sobie z tym poradzić:

show_args(*{'arg_2':'two', 'arg_1':'one'})
arg_2
arg_1

Jedna gwiazdka jakoś już pomogła, niestety, pewnie wolelibyśmy nie zobaczyć w wyniku funkcji nazw kluczy, tylko ich wartości! Z pomocą przyjdą dwie gwiazdki, które konwertują słownik na nazwane wartości przekazywane do funkcji:

show_args(**{'arg_2':'two', 'arg_1':'one'})
one
two

I to już działa idealnie. Funkcja domyśliła się, co to jest arg_1 mimo tego, że ta wartość w słowniku była dopiero na drugim miejscu.

Fajnie, ale te „chwyty” można też wykorzystać definiując funkcję:

def clever_function(*args):
   for a in args:
      print(a)

clever_function(1,2,3)

Kiedy chcesz, aby funkcja mogła przyjąć dowolną liczbę parametrów przekazywanych po prostu przez pozycję, to wystarczy zadeklarować argumenty jako  *args. W ciele funkcji można wtedy skorzystać ze zmiennej args, która jest listą.  Bardzo to elastyczne!

Jeśli z kolei chcesz, aby funkcja miała przyjmować dowolną liczbę argumentów ze słownika, to argument poprzedź dwoma gwiazdkami. Zazwyczaj ten parametr nazywamy kwargs (key-word argument):

def clever_function(**kwargs):
   for k, v in kwargs.items():
      print(k,v)

clever_function(a=1,b=2,c=3)

Teraz do funkcji można przekazywać dowolną liczbę nazwanych parametrów, a funkcja w sprytny sposób zobaczy je jako słownik. To użytkownik wywołując funkcję sam decyduje o tym, jak mają się nazywać argumenty widoczne w funkcji.

Obie te metody można zresztą połączyć i zbudować funkcję tak:

def clever_function(*args, **kwargs):
   for a in args:
      print(a)
 
   for k, v in kwargs.items():
      print(k,v)

clever_function('one','two',a=1,b=2,c=3)
print('---')
clever_function(a=1,b=2,c=3)
print('---')
clever_function('one','two')

Jak widać funkcję można teraz wywoływać z argumentami określanymi przez pozycję i nazwę, albo tylko przez nazwę albo tylko przez pozycję.

Oj przyda się na pewno!

Komentarze są wyłączone

Autor: Rafał Kraik