Cześć, w tym wpisie z kategorii BiteSize zajmiemy się rozpakowywaniem zmiennych iterowalnych (ang. iterables unpacking) i zobaczysz, po co i dlaczego warto je stosować. Poprawimy czytelność kodu i będziemy mogli się pozbyć wielu magicznych liczb (ang. magic numbers).
Problem do rozwiązania
Mamy listę krotek (list of tuples) rankingu konkursu. Każda krotka składa się z imienia i ilości zdobytych punktów. Następnie chcemy podać zwycięzców (3 miejsca z podium) i sprawdzić, jaki był najgorszy wynik. Przykładowe dane przedstawiam poniżej. Zakładam, że lista jest posortowana po ilości punków.
ranking = [ ("Michał", 139), ("Zosia", 123), ("Kasia", 112), ("Grzesiek", 99), ("Łukasz", 85), ..., ("Wojtek", 34), ]
Przykładowe rozwiązanie
Wiedząc, że tak jak wszyscy programiści liczymy od zera, a indeks -1 oznacza ostatni element, można łatwo napisać taki kod.
first = ranking[0] second = ranking[1] third = ranking[2] others = ranking[3:-1] last = ranking[-1] # Same thing in one line first, second, third, others, last = ranking[0], ranking[1], ranking[2], ranking[3:-1], ranking[-1] print(f"First place for {first[0]} with {first[1]} points.") print(f"Second place for {second[0]} with {second[1]} points.") print(f"Third place for {third[0]} with {third[1]} points.") print(f"Smallest number of points gotten is {last[1]}.")
Jest to całkiem okej i nie ma co się tutaj zbytnio kłócić. Jednak jak to często powtarza jeden z core developerów języka Python:
There must be a better way!
Raymond Hettinger
Jestem zwolennikiem podejścia – „Najpierw ma działać” oraz czasami „Jak działa, to nie ruszaj„. Co nie znaczy, że nie można bardziej Pythonowo.
Iterables unpacking
Jedno z pytań, które się nasuwa to, czym są iterables? Na potrzeby tego wpisu, powiem tylko, że to zmienne, po których możemy iterować. Zresztą jak na to sama nazwa wskazuje.
Wykorzystując rozpakowywanie, możemy zapisać to w następujący sposób.
first, second, third, *others, last = ranking print(f"First place for {first[0]} with {first[1]} points.") print(f"Second place for {second[0]} with {second[1]} points.") print(f"Third place for {third[0]} with {third[1]} points.") print(f"Smallest number of points gotten is {last[1]}.")
Zauważ, jak mało miejsca zajmuje kod i jest bardziej przejrzysty.
Jak to działa?
Pierwszy element listy ranking trafia do zmiennej first, drugi do zmiennej second, trzeci analogicznie. Do zmiennej last przypisany jest ostatni element. Natomiast pytanie brzmi, co oznacza gwiazdka (ang. appendix)?
W tym przypadku określane są konkretne miejsca, w których zależy nam na danych, czyli 1, 2 i 3 miejsce oraz ostatnie. Natomiast reszta jest nie do końca potrzebna, dlatego przypisujemy ją do zmiennej others.
Domyślasz się pewnie, że zmienne first, second, third oraz last to zmienne typu tuple. Natomiast jakiego typu jest zmienna others?
Chwila na zastanowienie…
Masz rację! – To lista krotek. Po prostu wszystkie inne rekordy rankingu trafiają do listy. Źle odpowiedziałeś / odpowiedziałaś? – Nie ma to żadnego znaczenia, bo TERAZ już wiesz 🙂
Tak samo będzie z innymi zmiennymi, w tym przypadku są to tuple, a w innym mogą być liczby, tekst, słowniki lub w zasadzie… cokolwiek 😛
Wnioski i podsumowanie
Skoro już wiemy, jak można to zapisać i jak to działa powiem o kilku korzyściach, idących z używania tego sposobu.
- Stosujemy się do
Zen of Python
. – Beautiful is better than ugly. - Wartości mamy od razu przypisane do zmiennych, które możemy wykorzystać.
- Odczyt danych mamy w jednym miejscu. W przypadku składni
ranking[0]
możemy mieć to rozrzucone po pliku i nie do końca kontrolować przepływ danych, które mogły zostać zmienione w trakcie działania kodu. - Pozbywamy się magic numbers z nawiasów kwadratowych.
- Python posiada mechanizmy do tego i nasz kod będzie bardziej Pythonowy.
- Dobrze znać różne podejścia, aby wykorzystać to odpowiednie do naszego problemu.
Dzięki za dotarcie do końca! Jeżeli spodobał Ci się wpis, to proszę, przekaż link 1 osobie, której może się on spodobać.
Interesuje Cię jakiś konkretny temat? – Napisz! Tematy cieszące się największym zainteresowaniem pójdą na pierwszy plan :). Inne wpisy z segmentu BiteSize znajdziesz tu.
~ Marek