Python jest najczęściej używanym językiem programowania. Dzisiaj nauczysz się korzystać z jednej z jego podstawowych — ale często ignorowanych — funkcji — rozpakowywania w Pythonie.
Prawdopodobnie widziałeś * i ** w kodzie innych, a nawet używałeś ich, nie wiedząc, jaki jest ich cel. Będziemy omawiać koncepcję rozpakowywania i jak jej używać do pisania większej ilości kodu w Pythonie.
Oto lista pojęć, które okażą się przydatne podczas czytania tego samouczka:
- Iterowalna: Dowolna sekwencja, którą można iterować za pomocą pętli for, na przykład zestawy, listy, krotki i słowniki
- Wywoływalny: Obiekt Pythona, który można wywołać za pomocą podwójnych nawiasów (), na przykład myfunction()
- Shell: Interaktywne środowisko uruchomieniowe, które pozwala nam uruchamiać kod Pythona. Możemy to wywołać, uruchamiając „python” w terminalu
- Zmienna: Nazwa symboliczna, która przechowuje obiekt i ma zarezerwowaną lokalizację w pamięci.
Zacznijmy od najczęstszego nieporozumienia: asterystyka w Pythonie to także operatory arytmetyczne. Jedna gwiazdka
służy do mnożenia, a dwa z nich (**) odnoszą się do potęgowania.
>>> 3*3 9 >>> 3**3 27
Możemy to udowodnić, otwierając powłokę Pythona i wpisując:
Uwaga: aby móc korzystać z tego samouczka, musisz mieć zainstalowany Python 3. Jeśli nie masz go zainstalowanego, sprawdź nasz przewodnik instalacji Pythona.
Jak widać, używamy gwiazdki po pierwszej liczbie i przed drugą. Kiedy to widzisz, oznacza to, że używamy operatorów arytmetycznych.
>>> *range(1, 6), (1, 2, 3, 4, 5) >>> {**{'vanilla':3, 'chocolate':2}, 'strawberry':2} {'vanilla': 3, 'chocolate': 2, 'strawberry': 2}
Z drugiej strony używamy gwiazdek (*, **) przed iteracją, aby ją rozpakować — na przykład:
Spis treści:
Nie martw się, jeśli tego nie zrozumiesz, to tylko wstęp do rozpakowywania w Pythonie. Więc śmiało i przeczytaj cały samouczek!
Co się rozpakowuje?
Rozpakowywanie to proces wydobywania rzeczy — elementów iterowalnych, takich jak listy, krotki i słowniki. Pomyśl o tym jak o otwarciu pudełka i wyjęciu różnych przedmiotów, takich jak kable, słuchawki lub USB.
Rozpakowywanie w Pythonie jest podobne do rozpakowywania pudełka w prawdziwym życiu.
>>> mybox = ['cables', 'headphones', 'USB'] >>> item1, item2, item3 = mybox
Przetłumaczmy ten sam przykład na kod dla lepszego zrozumienia:
Jak widać, przypisujemy trzy elementy z listy mybox do trzech zmiennych item1, item2, item2. Ten rodzaj przypisania zmiennych jest podstawową koncepcją rozpakowywania w Pythonie.
>>> item1 'cables' >>> item2 'headphones' >>> item3 'USB'
Jeśli spróbujesz uzyskać wartość każdej pozycji, zauważysz, że pozycja 1 odnosi się do „kable”, pozycja 2 odnosi się do „słuchawek” i tak dalej.
>>> newbox = ['cables', 'headphones', 'USB', 'mouse'] >>> item1, item2, item3 = newbox Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: too many values to unpack (expected 3)
Do tego momentu wszystko wydawało się być w porządku z tym kodem, ale co by było, gdybyśmy chcieli rozpakować listę z większą liczbą elementów — zachowując tę samą liczbę przypisanych zmiennych?
Prawdopodobnie spodziewałeś się tego rodzaju błędu. Zasadniczo przypisujemy 4 elementy listy do trzech zmiennych, w jaki sposób Pythonowi udaje się przypisać właściwe wartości? Nie ma, to dlatego, że dostajemy Błąd wartości
z komunikatem „zbyt wiele wartości do rozpakowania”. Dzieje się tak, ponieważ ustawiamy trzy zmienne po lewej stronie i cztery wartości (odpowiadające liście newbox) po prawej stronie.
>>> lastbox = ['cables', 'headphones'] >>> item1, item2, item3 = lastbox Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: not enough values to unpack (expected 3, got 2)
Jeśli spróbujesz wykonać podobny proces, ale z większą liczbą zmiennych niż wartości do rozpakowania, otrzymasz kolejny błąd wartości, z tym wyjątkiem, że z nieco innym komunikatem:
Uwaga: Pracowaliśmy z listami, ale możesz użyć tej formy rozpakowywania z dowolnymi iterowalnymi (listami, zestawami, krotkami, słownikami)
Jak zatem przezwyciężyć tę sytuację? Czy jest jakiś sposób na rozpakowanie wszystkich elementów iterowalnego do kilku zmiennych bez żadnych błędów?
Jasne, że istnieje i nazywa się to operatorem rozpakowywania lub operatorem gwiazdki (*, **). Zobaczmy, jak go używać w Pythonie.
Jak rozpakowywać listy za pomocą operatora *
Operator gwiazdki
>>> first, *unused, last = [1, 2, 3, 5, 7] >>> first 1 >>> last 7 >>> unused [2, 3, 5]
służy do rozpakowania wszystkich wartości elementu iterowalnego, które nie zostały jeszcze przypisane.
>>> first, *_, last = [1, 2, 3, 5, 7] >>> _ [2, 3, 5]
Załóżmy, że chcesz uzyskać pierwszy i ostatni element listy bez użycia indeksów, możemy to zrobić za pomocą operatora gwiazdki:
>>> first, *_, last = [1, 2] >>> first 1 >>> last 2 >>> _ []
Jak możesz docenić, otrzymujemy wszystkie nieużywane wartości za pomocą operatora gwiazdki. Preferowanym sposobem odrzucania wartości jest użycie zmiennej podkreślenia (_), która jest czasami używana jako „zmienna fikcyjna”.
Nadal możemy korzystać z tej sztuczki, nawet jeśli lista zawiera tylko dwa elementy:
W tym przypadku zmienna podkreślenia (zmienna fikcyjna) przechowuje pustą listę, więc pozostałe dwie zmienne wokół niej mają dostęp do dostępnych wartości listy.
>>> *string = 'PythonIsTheBest'
Wspólne rozwiązywanie problemów
>>> *string = 'PythonIsTheBest' File "<stdin>", line 1 SyntaxError: starred assignment target must be in a list or tuple
Możemy rozpakować unikalny element iterowalnego. Na przykład wymyśliłbyś coś takiego: Jednak powyższy kod zwróci błąd SyntaxError:To dlatego, że wg
Specyfikacja PEP
:
>>> *string, = 'PythonIsTheBest' >>> string ['P', 'y', 't', 'h', 'o', 'n', 'I', 's', 'T', 'h', 'e', 'B', 'e', 's', 't']
Krotka (lub lista) po lewej stronie prostego przypisania
>>> *numbers, = range(5) >>> numbers [0, 1, 2, 3, 4]
Jeśli chcemy rozpakować wszystkie wartości zmiennej iterowalnej do jednej zmiennej, musimy ustawić krotkę, stąd wystarczy dodanie prostego przecinka:
Innym przykładem może być użycie funkcji zakresu, która zwraca sekwencję liczb.
Teraz, gdy wiesz, jak rozpakowywać listy i krotki z gwiazdką, nadszedł czas, aby przejść do rozpakowywania słowników.
Jak rozpakować słowniki za pomocą operatora **
>>> **greetings, = {'hello': 'HELLO', 'bye':'BYE'} ... SyntaxError: invalid syntax
Podczas gdy pojedyncza gwiazdka jest używana do rozpakowywania list i krotek, podwójna gwiazdka (**) jest używana do rozpakowywania słowników.
>>> food = {'fish':3, 'meat':5, 'pasta':9} >>> colors = {'red': 'intensity', 'yellow':'happiness'} >>> merged_dict = {**food, **colors} >>> merged_dict {'fish': 3, 'meat': 5, 'pasta': 9, 'red': 'intensity', 'yellow': 'happiness'}
Niestety, nie możemy rozpakować słownika do pojedynczej zmiennej, tak jak robiliśmy to z krotkami i listami. Oznacza to, że następujące polecenie zgłosi błąd:
Możemy jednak użyć operatora ** wewnątrz callables i innych słowników. Na przykład, jeśli chcemy utworzyć połączony słownik utworzony z innych słowników, możemy użyć poniższego kodu:
Jest to dość krótki sposób tworzenia słowników złożonych, jednak nie jest to główne podejście do rozpakowywania w Pythonie.
Zobaczmy, jak możemy wykorzystać rozpakowywanie z wywołaniami
Pakowanie w funkcje: argumenty i kwargi
Prawdopodobnie widziałeś argumenty i kwargi przed implementacją w klasach lub funkcjach. Zobaczmy, dlaczego musimy ich używać wraz z wywołaniami.
>>> def product(n1, n2): ... return n1 * n2 ... >>> numbers = [12, 1] >>> product(*numbers) 12
Pakowanie z operatorem * (args)
>>> product(12, 1) 12
Załóżmy, że mamy funkcję, która oblicza iloczyn dwóch liczb.
>>> numbers = [12, 1, 3, 4] >>> product(*numbers) ... TypeError: product() takes 2 positional arguments but 4 were given
Jak widać, rozpakowujemy numery list do funkcji, więc faktycznie wykonujemy następujące czynności:
>>> def product(*args): ... result = 1 ... for i in args: ... result *= i ... return result ... >>> product(*numbers) 144
Do tego momentu wszystko działa dobrze, ale co by było, gdybyśmy chcieli przekazać dłuższą listę? Z pewnością zgłosi błąd, ponieważ funkcja otrzymuje więcej argumentów, niż jest w stanie obsłużyć.
Możemy rozwiązać ten problem, po prostu umieszczając listę bezpośrednio w funkcji, co tworzy w niej element iterowalny i pozwala nam przekazać do funkcji dowolną liczbę argumentów.
Tutaj traktujemy parametr args jako iterowalny, przechodząc przez jego elementy i zwracając iloczyn wszystkich liczb. Zwróć uwagę, że początkowa liczba wyniku musi wynosić jeden, ponieważ jeśli zaczniemy od zera, funkcja zawsze zwróci zero. Uwaga: args to tylko konwencja, możesz użyć dowolnej innej nazwy parametruMożemy również przekazać do funkcji dowolne liczby bez użycia listy, tak jak w przypadku funkcji wbudowanej
>>> product(5, 5, 5) 125 >>> print(5, 5, 5) 5 5 5
funkcja drukowania
>>> def test_type(*args): ... print(type(args)) ... print(args) ... >>> test_type(1, 2, 4, 'a string') <class 'tuple'> (1, 2, 4, 'a string')
.
Na koniec pobierzmy typ obiektu argumentów funkcji.
Jak zauważono w powyższym kodzie, typem args będzie zawsze krotka, a jej treścią będą wszystkie argumenty nie będące słowami kluczowymi przekazane do funkcji.
Pakowanie z operatorem ** (kwargs)
>>> def make_person(name, **kwargs): ... result = name + ': ' ... for key, value in kwargs.items(): ... result += f'{key} = {value}, ' ... return result ... >>> make_person('Melissa', id=12112, location='london', net_worth=12000) 'Melissa: id = 12112, location = london, net_worth = 12000, '
Jak widzieliśmy wcześniej, operator ** jest używany wyłącznie w przypadku słowników. Oznacza to, że za pomocą tego operatora możemy przekazywać pary klucz-wartość do funkcji jako parametr.
Stwórzmy funkcję make_person, która otrzyma argument pozycyjny „nazwa” i nieokreśloną liczbę argumentów ze słowami kluczowymi.
Jak widać, instrukcja **kwargs konwertuje wszystkie argumenty ze słowami kluczowymi na słownik, który możemy iterować wewnątrz funkcji.
>>> def test_kwargs(**kwargs): ... print(type(kwargs)) ... print(kwargs) ... >>> test_kwargs(random=12, parameters=21) <class 'dict'> {'random': 12, 'parameters': 21}
Uwaga: kwargs to tylko konwencja, w której możesz nazwać ten parametr, jak chcesz
Możemy sprawdzić typ kwarg w taki sam sposób, jak zrobiliśmy to z argumentami:
>>> def my_final_function(*args, **kwargs): ... print('Type args: ', type(args)) ... print('args: ', args) ... print('Type kwargs: ', type(kwargs)) ... print('kwargs: ', kwargs) ... >>> my_final_function('Python', 'The', 'Best', language="Python", users="A lot") Type args: <class 'tuple'> args: ('Python', 'The', 'Best') Type kwargs: <class 'dict'> kwargs: {'language': 'Python', 'users': 'A lot'}
Zmienna wewnętrzna kwargs zawsze staje się słownikiem, w którym przechowywane są pary klucz-wartość przekazane do funkcji.
Na koniec użyjmy argumentów i kwarg w tej samej funkcji:
Wniosek
- Operatory rozpakowywania są bardzo przydatne w codziennych zadaniach, teraz wiesz, jak ich używać zarówno w poszczególnych instrukcjach, jak i parametrach funkcji.
- W tym samouczku nauczyłeś się:
- Używasz * dla krotek i list, a ** dla słowników
- Operatorów rozpakowujących można używać w konstruktorach funkcji i klas
args służą do przekazywania do funkcji parametrów innych niż słowa kluczowekwargs służą do przekazywania parametrów ze słowami kluczowymi do funkcji.