Zadanie z gwiazdką, czyli rzecz o *args i **kwargs

*args i ** kwargs

Często spotykamy się z funkcjami, które wśród argumentów zawierają „magiczne” wyrażenia *args i **kwargs. Jednak początkujący programiści Pythona miewają problemy ze zrozumieniem działania tego mechanizmu.

Zacznijmy od odpowiedzenia sobie na pytanie czym są te „argsy i kwargsy” i czemu poprzedzają je gwiazdki. Wyrażenie „args” bierze się z od słowa „arguments” czyli argumenty i jest to zazwyczaj zmienna, która zawiera tuple argumentów pozycyjnych. Natomiast „kwargs” bierze się od „keyword arguments” czyli argumenty nazwane i zmienna taka zawiera pary nazwa-wartość argumentu. Jednak należy zaznaczyć, że nazwy te nie są wcale najważniejsze. Największa magia kryje się w gwiazdkach je poprzedzających, a „args” i „kwargs” możemy zastąpić dowolnymi innymi nazwami zmiennych.

Umieszczając w definicji funkcji wyrażenie z jedną lub dwoma gwiazdkami pozwalamy na przekazywanie do niej argumentów w dowolniej liczbie i nazwie. Bez konieczności konkretnego określenia tych parametrów. Jest to przydatne w momencie gdy chcemy, aby nasza funkcja była nieco bardziej uniwersalna.

Po pierwsze: *args

Wyrażenia z jedną gwiazdką (*) używamy gdy do funkcji  chcemy przekazać dowolną liczbę argumentów pozycyjnych. Czyli takich dla których przy wywołaniu funkcji nie podajemy ich nazwy, a przypisanie wartości bazuje na kolejności argumentów. Z tego powodu parametr *args umieszczamy na końcu listy parametrów w definicji funkcji.

def parametr_args(argument, *args):
    print("zawartość args: {}".format(args))
    print("argument nazwany: {}".format(argument))
    for arg in args:
        print("argument z *args: {}".format(arg))

parametr_args('python', 'spam', 'eggs', 'test')

Możesz zauważyć, że wywołując powyższą funkcję przekazaliśmy w jej wywołaniu więcej argumentów niż zadeklarowaliśmy. Nadmiarowe argumenty zostały umieszczone w tupli po której z łatwością możemy iterować, aby dostać się do tych argumentów.

Po drugie: **kwargs

W przypadku gdy do naszej funkcji chcemy przekazywać argumenty, które wyróżniają się nazwą możemy użyć parametru z dwoma gwiazdkami (**). Przekazane w ten sposób argumenty są dostępne w funkcji w postaci słownika. Jego pary klucz-wartość stanowią nazwa i wartość przekazanego argumentu.

def parametr_kwargs(argument, **kwargs): 
    print("argument: {}".format(argument))
    print("zawartość kwargs: {}".format(kwargs))

parametr_kwargs(dodatkowy=48, nastepny=111, argument=12) 

# argument: 12 
# zawartość kwargs: {'dodatkowy': 48, 'nastepny': 111}

Jak widzisz w powyższym przykładzie argumenty, które nie zostały zdefiniowane w funkcji trafiły do słownika o nazwie kwargs.

Jak używać gwiazdek w *args i **kwargs?

Możesz również używać obu poznanych przed chwilą parametrów. W tym przypadku pamiętaj jedynie o kolejności – wyrażenie z dwoma gwiazdkami musi być na końcu, z jedną gwiazdką wcześniej, a pozostałe zdefiniowane argumenty na początku.

Gwiazdek możesz również używać w wywołaniu funkcji. Jest to tak zwane rozpakowywanie list i słowników z argumentami. Jeżeli funkcja przyjmuje kilka argumentów i posiadasz listę, która zawiera argumenty, które chcesz przekazać do tej funkcji wystarczy poprzedzić nazwę listy gwiazdką zamiast podawać kolejne argumenty ręcznie.

lista_argumentow = [1,3,5] 
def rozpakowywanie(pierwszy, drugi, trzeci):
    print(pierwszy)
    print(drugi)
    print(trzeci) 

rozpakowywanie(*lista_argumentow) 

# 1 
# 3 
# 5

Przyznasz, że ten sposób wygląda dużo lepiej niż:

rozpakowywanie(lista_argumentow[0], lista_argumentow[1], lista_argumentow[2])

Mam nadzieję, że ten artykuł rozjaśnił Ci działanie gwiazdek w Pythonie. Jeżeli masz jeszcze jakieś pytanie dotyczące działania tego mechanizmu zapraszam do zostawienia komentarza.

Jeżeli dopiero zaczynasz swoją przygodę z Pythonem lub jesteś bardziej zaawansowany sprawdź jak może pomóc Ci Jupyter Notebook.


A może potrzebujesz pomocy w nauce programowania i nie wiesz do kogo zwrócić się z pytaniami? Zajrzyj na stronę O Blogu znajdziesz tam więcej szczegółów na temat prowadzonego przeze mnie mentoringu.

Spodobał Ci się ten artykuł, sprawdź też pozostałe wpisy na moim blogu:




6 komentarzy

Masz błąd w linijce parametr_kwargs(dodatkowy=48, nastepny=111, argument=12).
Sam napisałeś, że zdefiniowany argument powinien być na początku ^_^

Hej, tak jak napisałem, zdefiniowany argument powinien być na początku, ale tyczy się to przede wszystkim definicji funkcji. Oznacza to, że nie możemy zrobić czegoś takiego:
def parametr_kwargs(**kwargs, argument):

W wywołaniu funkcji powinien on być na początku, gdy chcemy go wywołać bez nazwy:
parametr_kwargs(12, dodatkowy=48, nastepny=111)

Natomiast jeżeli wywołujemy funkcję podając jej argumenty z ich nazwami, to argumenty te możemy podać w dowolnej kolejności.

cześć mam pytanie czy mając funkcje która przyjmuje na wejściu argument *args
mogę jakoś odwołać się do jej pierwszego argumentu bez użycia pętli tak jak chociażby w przykładzie poniżej:

def parametr_args(*args):
print(„zawartość args[0])

Cześć,
jeżeli jako jeden z argumentów funkcji podasz *args, to wewnątrz funkcji będziesz mieć dostępną zmienną args, która jest zwykłą tuplą. Oznacza to, że do pierwszego jej elementu możesz dostać się poprzez args[0].
Prosty przykład:

def parametr_args(*args):
 print(args)
  if len(args) > 0:
   print("Pierwszy argument: {}".format(args[0]))
  else:
   print("Brak argumentow")

Hej,
w jaki sposób mogę w argumentach funkcji zdefiniować dwa argumenty typu **kwargs i jeden *args?

Dla przykładu, mam napisać funkcję „opakuj”, która przyjmuje w argumentach wiele prezentów a także opcjonalnie argumenty nazwane „papier” i „wstążka”.

Próbowałam coś na zasadzie
def opakuj(*prezenty, **papier, **wstazka):
pass
jednak nie jest to prawidłowa konstrukcja.

Cześć,
w tym przypadku możesz zrobić to na przykład w taki sposób:
def opakuj(*prezenty, papier=None, wstazka=None)

Wtedy wszystkie nienazwane argumenty trafią do listy prezenty, natomiast papier i wstazka będą miały domyślną wartość None, która będziesz mogła nadpisać.
Przykładowe wywołania wyglądały by wtedy tak:
opakuj("puzzle", "lego")
opakuj("puzzle", "lego", papier="czerwony")
opakuj("puzzle", "lego", wstazka="w kropki")

Jeżeli chciałabyś użyć konstrukcji z **kwargsami to możesz zrobić coś w stylu:

def opakuj(*prezenty, **opakowanie):
    print(prezenty)
    print(opakowanie)

Wtedy wszystkie nienazwane argumenty trafią do listy prezenty, a nazwane do słownika opakowanie. W tym przypadku wywołanie
opakuj("puzzle", "lego", papier="czerwony")
powinno wypisać
("puzzle", "lego")
{"papier": "czerwony"}

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *