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:
- Magiczne metody – czyli szczypta magii w PythonieMoim zdaniem rzeczą, która należy wymienić na początku wśród tych, które sprawiają, że Python jest tak przyjazny poczatkującym użytkownikom jest jego wszechobecna spójność. Już… Czytaj więcej: Magiczne metody – czyli szczypta magii w Pythonie
- Pytest – ujarzmij fixtury i mockiJedną z najważniejszych rzeczy w trakcie pracy nad aplikacją jest zapewnienie tego, by miała ona jak najmniej błędów oraz żeby kolejne zmiany w kodzie… Czytaj więcej: Pytest – ujarzmij fixtury i mocki
- Co nowego w Python 3.8Obecnie najnowszą, oficjalną wersją języka jest wersja Python 3.8, wersja ta posiada kilka nowości względem poprzednich edycji Pythona. W tym wpisie przyjrzymy się pokrótce… Czytaj więcej: Co nowego w Python 3.8
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"}