article banner (priority)

Listy w Pythonie

Wyobraź sobie, że piszesz aplikację do sporządzania listy zakupów. Na Twojej liście może się znajdować dowolna liczba produktów. Jeśli więc chcesz taką listę przechowywać w zmiennej, to jak to zrobić? Do tej pory nasze zmienne przechowywały pojedyncze wartości, a tu potrzebujemy przechowywać nieokreśloną ich liczbę. W Pythonie używamy do tego listy (ang. list), która reprezentuje zbiór wartości. Wartości mają na niej swoją kolejność oraz mogą się powtarzać. Listy mogą się także zmieniać, w przeciwieństwie do tupli, o których pomówimy później.

Listy są jednym z najistotniejszych bloków budujących programy. Spójrz tylko na pierwszy lepszy sklep internetowy, a dostrzeżesz tam listę produktów (a one mają swoje listy rozmiarów i wariantów), listę sprzedawców, klientów, metod dostawy, metod płatności... Wszędzie listy. Teraz spójrz na Facebooka. Wchodzisz i widzisz listę wpisów, znajomych, odpowiedzi i polubień. Dowolna publikacja internetowa to lista artykułów, lista autorów, lista komentarzy, lista kategorii... Chyba rozumiesz. Nic dziwnego, że są one takie ważne. Poznajmy więc, jak działają oraz w jaki sposób możemy z nich korzystać.

Tworzenie list

Lista koncepcyjnie przypomina nieskończenie wielką półkę. Przedmioty możemy umieszczać na niej na kolejnych ponumerowanych miejscach, zaczynając od 0.

Listę można sobie wyobrażać jak nieskończenie dużą półkę, gdzie miejsca na wartości ponumerowane są kolejnymi liczbami zaczynając od zera.

W Pythonie listę tworzymy za pomocą nawiasów kwadratowych. Gdy zostawimy je puste, to powstanie pusta lista, czyli bez żadnych elementów.

my_list = []
print(my_list)  # []

list to nie jest dobra nazwa dla zmiennej, gdyż jest to nazwa klasy reprezentującej listę.

Często od razu chcemy utworzyć listę zawierającą określone wartości. Umieszczamy je wewnątrz nawiasów, oddzielając je przecinkami.

fruits = ["Jabłko", "Banan", "Śliwka"]
print(fruits)  # ["Jabłko", "Banan", "Śliwka"]

Wizualizacja listy z trzema elementami — jabłkiem, bananem i śliwką. Zajmują one kolejne pozycje od 0 do 2.

W listach, podobnie jak w zmiennych, możemy przechowywać elementy różnego typu.

my_list = [1, "A", True, [], {a: "A"}]
print(my_list)  # [1, "A", True, [], {a: "A"}]

W praktyce jednak niemal zawsze w jednej liście używamy elementów tego samego typu. Bardzo często lista zawiera obiekty danej klasy, na przykład produkty, użytkownicy, lekarze czy gry.

Dodawanie i wyciąganie elementów

W Pythonie możemy zmieniać zawartość listy poprzez dodawanie lub wyciąganie elementów. Dodajemy element na koniec listy przy użyciu metody append. Tak jak w przypadku naszej metafory półki, kiedy kładziesz nowy przedmiot, to domyślnie umieszczasz go na pierwszej wolnej pozycji za innymi elementami.

fruits = ["Jabłko"]
print(fruits)  # ["Jabłko"]

fruits.append("Banan")
print(fruits)  # ["Jabłko", "Banan"]

fruits.append("Śliwka")
print(fruits)  # ["Jabłko", "Banan", "Śliwka"]

Metoda append dodaje element do listy na ostatniej pozycji.

Możemy też wyciągać elementy. Najpowszechniejszy sposób oferuje metoda pop, która bierze ostatni element z listy. Do złudzenia przypomina ona wyciągnięcie ostatniej rzeczy z półki. Przy wywołaniu tej metody zwraca ona wyciągnięty element, a jednocześnie modyfikuje listę tak, że element z niej znika.

fruits = ["Jabłko", "Banan", "Śliwka"]
ret = fruits.pop()
print(ret)  # Śliwka
print(fruits)  # ["Jabłko", "Banan"]

Metoda pop wyciąga ostatni element z listy.

Uważaj, by nie próbować wyciągać elementów z pustej listy, gdyż jest to błąd prowadzący do wyjątku, przerywającego działanie programu.

Ćwiczenie: Tworzenie i modyfikacja listy

Uzupełnij luki.

values = [True, __, "AAA"]
print(values.pop())  # ____
print(values.pop())  # 42
values.append(88)
print(values)  # _______

pets = ["dog", "cat"]
pets.pop()
pets.append("pig")
print(pets)  # _______
pet = pets.pop()
print(pets)  # _______
print(pet)  # _______

Odpowiedzi na końcu książki.

Odnoszenie się do elementów listy

Wracając do przywołanej już metafory półki, najprostszym sposobem na odniesienie się do elementów, jest użycie numerów, które znajdują się pod nimi. Są to tak zwane indeksy elementów. Indeks dla pierwszego elementu to zawsze zero1.

Czasami funkcjonuje też określenie pozycji elementów, ale pojęcie to nie jest tak jednoznacznie rozumiane. Niektórzy o elemencie na indeksie 0 mówią, że znajduje się na pierwszej pozycji. By uniknąć niespójności w rozumieniu tego terminu wśród programistów, trzymać się będziemy określania, na jakim indeksie znajduje się dany element.

Aby pobrać element o danym indeksie, używamy nawiasów kwadratowych za listą2. Taka operacja nie wpływa na zawartość listy, pozwala nam się tylko odnieść do jednego z elementów.

fruits = ["Jabłko", "Banan", "Śliwka"]
print(fruits)  # ["Jabłko", "Banan", "Śliwka"]

print(fruits[1])  # Banan

print(fruits[0])  # Jabłko

print(fruits)  # ["Jabłko", "Banan", "Śliwka"]

fruit = fruits[2]
print(fruit)  # Śliwka

Jeśli chcemy odnieść się do pierwszego elementu, to używamy indeksu 0. Jak do drugiego to 1. Co jednak, jeśli chcemy się odnieść do ostatniego elementu? Jeśli byśmy znali wielkość listy, to odjęlibyśmy od niej 1 i byłby to właśnie indeks ostatniego elementu. Taka operacja byłaby jednak dość skomplikowana, a więc Python uprościł nam sprawę. Jeśli chcemy się odnieść do ostatniego elementu, to używamy wartości -1. Do przedostatniego -2 itp.

fruits = ["Jabłko", "Banan", "Śliwka"]
print(fruits)  # ["Jabłko", "Banan", "Śliwka"]

print(fruits[-1])  # Śliwka

print(fruits[-2])  # Banan

print(fruits)  # ["Jabłko", "Banan", "Śliwka"]

fruit = fruits[-3]
print(fruit)  # Jabłko

Ćwiczenie: Odnoszenie się do elementów listy

Co zostanie wypisane w wyniku działania poniższego kodu?

names = ["Ada", "Bartek", "Czarek", "Daria", "Ewa"]

print(names[0])
print(names[3])
print(names[-1])
print(names[-2])
print(names[1])
print(names[-4])

Odnoszenie się elementów przy pomocy zakresu

Kolejną przydatną funkcjonalnością jest możliwość odnoszenia się elementu w pewnym zakresie indeksów. Zakres określamy poprzez podanie najpierw od jakiego indeksu elementy nas interesują, następnie dwukropka, a następnie przed jakim indeksem mamy skończyć. Na przykład, jeśli interesują nas elementy od drugiego do przedostatniego, to powinniśmy użyć indeksu drugiego elementu (czyli 1) oraz ostatniego (czyli -1), a więc 1:-1.

letters = ["A", "B", "C", "D"]

print(letters[1:-1])  # ['B', 'C']
print(letters[0:-2])  # ['A', 'B']
print(letters[0:-1])  # ['A', 'B', 'C']

Aby określić zakres, który nie ma górnego ograniczenia, nie stawiamy nic po prawej stronie dwukropka. Podobnie, jeśli po lewej stronie nie postawimy wartości, oznaczać to będzie zakres zaczynający się na samym początku. Samotny dwukropek oznacza więc zakres obejmujący wszystkie elementy.

letters = ["A", "B", "C", "D"]

print(letters[2:])  # ['C', 'D']
print(letters[1:])  # ['B', 'C', 'D']
print(letters[:2])  # ['A', 'B']
print(letters[:])  # ['A', 'B', 'C', 'D']

Indeksów i zakresów można używać także do wyciągania fragmentów stringów, gdzie indeksy odpowiadają kolejnym literom. Tak więc "ABC"[1] zwróci "B", a "ABCDEF"[1:-1] zwróci "BCDE".

Ćwiczenie: Odnoszenie się elementów przy pomocy zakresu

Co zostanie wypisane w wyniku działania poniższego kodu?

names = ["Ada", "Bartek", "Czarek", "Daria", "Ewa"]

print(names[0:2])
print(names[2:4])
print(names[:3])
print(names[3:-1])
print(names[1:])
print(names[1:3])
print(names[-3:])
print(names[1:-2])
print(names[:])

Zmiana elementów przy użyciu zakresu

Przy użyciu indeksów i zakresów możemy także wskazywać wartości, które chcemy zmienić. Zmiana elementu na indeksie wygląda identycznie jak odnoszenie się do niego, ale dodatkowo musimy postawić znak równości (oznaczający przypisanie) i nową wartość.

names = ["Ada", "Bartek", "Czarek"]

names[1] = "Marek"
print(names)  # ['Ada', 'Marek', 'Czarek']

names[-1] = "Nina"
print(names)  # ['Ada', 'Marek', 'Nina']

Analogicznie z zamianą elementów w zakresie. Tylko tutaj po prawej stronie powinniśmy postawić nową listę, której elementy powinny zastąpić elementy w podanym zakresie.

names = ["Ada", "Bartek", "Czarek", "Daria"]

names[1:3] = ["Ola"]
# W zakresie 1:3 był "Bartek" i "Czarek",
# teraz jest "Ola"
print(names)  # ['Ada', 'Ola', 'Daria']

names[1:2] = ["Paulina", "Robert"]
# W zakresie 1:2 była "Ola"
# teraz jest "Paulina" i "Robert"
print(names)  # ['Ada', 'Paulina', 'Robert', 'Daria']

names[2:] = []
# Usuwamy elementy od indeksu drugiego
print(names)  # ['Ada', 'Paulina']

names[:1] = []
# Usuwamy pierwszy element
print(names)  # ['Paulina']

names[:] = []
# Tak możemy wyczyścić całą listę
print(names)  # []

Ćwiczenie: Zmiana elementów listy

Co zostanie wypisane w wyniku działania poniższego kodu?

names = ["Ada", "Bartek", "Czarek"]

names[2] = "Figa"
print(names)

names[-2] = "Geralt"
print(names)

names = ["Ada", "Bartek", "Czarek"]

names[:1] = []
print(names)

names[2:] = ["Ewa", "Halina"]
print(names)

names[1:2] = ["Iza", "Jan"]
print(names)

names[:-1] = ["Kasia"]
print(names)

Wielkość listy

Niejednokrotnie interesuje nas liczba elementów listy. Sprawdzamy to przy użyciu funkcji len, która zwraca tę liczbę.

empty = []
print(len(empty))  # 0

names = ["Jabłko", "Banan"]
print(len(names))  # 2

values = [True, "Śliwka", None, [], 42]
print(len(values))  # 5
print(len(values[3]))  # 0

Ćwiczenie: Wielkość i elementy listy

Stwórz listę z kolejnymi literami od "A" do "F". Jaka będzie wielkość tej listy? Jaki jest indeks litery E? Następnie stwórz listę z kolejnymi numerami od 5 do 12. Jaka będzie wielkość tej listy? Jaki element znajduje się na pozycji (indeksie) 3?

letters = ______________________
print(len(letters))  # ____
print(letters[____])  # E

numbers = ______________________
print(len(numbers))  # ___
print(numbers[3])  # ___

Odpowiedzi na końcu książki.

Sprawdzanie obecności elementu na liście

Bardzo często potrzebujemy sprawdzić, czy lista zawiera dany element. Na przykład, jeśli tworzymy sklep i mamy listę przedstawiającą dostępne rozmiary koszulki, to możemy chcieć sprawdzić, czy wybrany przez użytkownika rozmiar jest dostępny. Sprawdzamy to poprzez użycie słówka in pomiędzy poszukiwanym elementem oraz listą.

sizes = ["M", "L", "XL", "XXL"]

print("L" in sizes)  # True
print("S" in sizes)  # False
print("XXL" in sizes)  # True

numbers = [3.14, 2.71, 42]

print(1 in numbers)  # False
print(2.71 in numbers)  # True
print(45 in numbers)  # False

Ćwiczenie: Sprawdzanie obecności elementu na liście

Co zostanie wypisane w wyniku działania poniższego kodu?

letters = ["A", "C", "E"]

print("A" in letters)
print("B" in letters)
print("C" in letters)

letters[1] = "F"
print("F" in letters)
print("C" in letters)

Dodawanie i kopiowanie list

Podobnie jak możemy dodać dwie liczby albo dwa stringi, tak możemy dodać dwie listy. W wyniku tej operacji powstaje nowa lista, zawierająca te same elementy co dodane listy.

list1 = [1, True]
list2 = ["A", []]
list3 = list1 + list2
print(list1)  # [1, True]
print(list2)  # ['A', []]
print(list3)  # [1, True, 'A', []]

list1[1] = False
print(list1)  # [1, False]
print(list3)  # [1, True, 'A', []]

Zauważ, że zmiana list1 nie wpływa na list3, gdyż list3 jest kopią połączonych list. Warto zwracać na to uwagę, bo jeśli mamy dwie zmienne wskazujące na jedną listę, to zmiana listy wpłynie na elementy wyświetlane dla obu zmiennych. Aby temu przeciwdziałać, tworzy się kopię listy (na przykład poprzez zakres obejmujący wszystkie elementy).

list1 = ["A", "B"]
list1Ref = list1
list1Copy = list1[:]

list1.append("C")
print(list1)  # ['A', 'B', 'C']
print(list1Ref)  # ['A', 'B', 'C']
print(list1Copy)  # ['A', 'B']

Ćwiczenie: Dodawanie i kopiowanie list

Co zostanie wypisane w wyniku działania poniższego kodu?

l1 = ["A", "B"]
l2 = ["D", "E"]
letters = l1 + l2
l1Copy = l1[:]
print(letters)

l1.append("C")
print(l1)
print(letters)
print(l1Copy)

Tuple

Poza listami, mamy w Pythonie także inne sposoby na wyrażenie zbioru danych. Warto wspomnieć krotkę (ang. tuple), zbiór (ang. set) czy słownik (ang. dictionary). Z nich wszystkich omówię tylko pierwszy, czyli tuple. Pozostałe dwa są również bardzo ciekawe, ale jednak mniej istotne i nie będą nam potrzebne w dalszych częściach.

Pojęcie "tuple" tłumaczy się jako "krotka". To tłumaczenie rzadko jest jednak używane poza książkami i kursami. Miałem w tym przypadku podobny dylemat co z tłumaczeniem stringów i tutaj również zdecydowałem się zostać przy tym (być może nie najpiękniejszym) spolszczeniu. Za używaniem pojęcia "tuple" przemawia większa zrozumiałość i łatwość przejścia na język angielski, który jest podstawą pracy programistów.

Tuple (tłumaczony jako "krotka") to niezmienny zbiór elementów, w którym elementy mają swoje pozycje. Tuple od listy różni się przede wszystkim tym, że nie można zmieniać jego elementów. Nie zadziała więc metoda append ani pop. Nie jest też dozwolona zamiana przy użyciu znaku równości po odniesieniu do elementu lub zakresu. Tuple tworzymy poprzez użycie nawiasu okrągłego zamiast klamrowego.

sizes = ("S", "M", "L", "XL")

print(len(sizes))  # 4
print(sizes[0])  # S
print(sizes[1:3])  # ('M', 'L')
print("XXL" in sizes)  # False
print("S" in sizes)  # True

Aby utworzyć tuple bez żadnych elementów, wystarczy pusty nawias. Możemy też użyć konstruktora tuple bez żadnych argumentów.

empty = ()
# albo
empty = tuple()
print(empty)  # ()

Jest jednak problem z utworzeniem tuple z pojedynczą wartością. Zwykły otaczający wartość jest przez Python interpretowany jako sposób na określenie kolejności operacji. Aby powstało tuple, musimy dodać przecinek za wartością.

s = ("XXL")
print(type(s))  # <class 'str'>

new_size = ("XXL",)
print(type(new_size))  # <class 'tuple'>

Tuple samo w sobie jest niezmienne, czyli zawsze wskazywać będzie na te same obiekty, ale możemy skonstruować nowe tuple na podstawie poprzedniego. W poniższym przypadku tworzymy nowe tuple poprzez dodanie sizesnew_size, po czym przypisujemy tę wartość do zmiennej sizes. Sama zawartość tuple się więc nie zmieniła, ale to na co wskazuje zmienna już tak.

sizes = sizes + new_size
print(sizes)  # ('S', 'M', 'L', 'XL', 'XXL')

Ćwiczenie: Tuple

Uzupełnij luki.

values = (True, __, "AAA")
print(values[1])  # 42
print(values[2])  # _____
print(values[:1])  # _____

empty = _______
print(len(empty))  # 0
single = _______
print(single)  # ('AAA',)
print(len(single))  # ___

Odpowiedzi na końcu książki.

Zakończenie

W tym rozdziale poznaliśmy listy oraz tuple. Dowiedzieliśmy się jak na nich operować, jak wyciągać ich elementy, a w przypadku list także jak je zmieniać. W następnym rozdziale poznamy nowe sposoby, jak przetwarzać listy.

1:

Tutaj zachodzi pewna rozbieżność względem tego, jak numeruje się elementy poza światem programowania. Dla przykładu: w hotelach zwykle zaczynamy od pokoju numer 1. Nie jest to jednak reguła. Coraz częściej spotykam się z hotelami, które numerują pokoje od 0, zupełnie jak w programowaniu. Także można powiedzieć, że parter jest piętrem zerowym. W przypadku programowania to przesunięcie w numeracji wynika z pierwszych języków programowania. Było wtedy optymalizacją. Zarówno nie marnowaliśmy liczby 0, jak i łatwiej było na podstawie adresu listy obliczyć adres elementu w pamięci.

2:

W domyśle za zmienną wskazującą na listę.