In [1]:
# setup
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

Listy

Lista to zmienna zawierająca zbiór elementów. Lista jest podstawowym i najczęściej używanym typem złożonym danych Pythona. Elementami listy mogą być wszystkie dostępne w języku Python typy danych, zarówno proste jak i złożone. Listy są jednym z najczęściej używanych typów danych.

Z punktu widzenia kodu, Lista jest uporządkowanym zbiorem elementów ograniczonym nawiasem kwadratowym. Ogólna postać listy:

lista = [element_1, element_2, …., element_n]

Note: znak \

znak \ pozwala na rozbicie długiej linii tekstu na krótsze linie i oznacza że linia jest kontynuowana w następnej linijce. Jest to niezwykle istotne, gdyż Python traktuje znak końca linii jako informację o kompletności polecenia. Większość języków programowania stosuje znaki specjalne oznaczające zakończenie polecenia oraz znaczające blok poleceń. W większości języków są to ; na oznaczenie końca polecenia oraz {} definiujące blok poleceń. Bloki poleceń zostaną omówione w kolejnej części kursu.

Jako przykład listy zbudujemy listę zawierającą nazwy poszczególnych miesięcy.

In [2]:
mce = ['styczen', 'luty', 'marzec', 'kwiecien', 'maj', \
       'czerwiec', 'lipiec', 'sierpien', 'wrzesien', \
       'pazdziernik', 'listopad', 'grudzien'] 
mce
type(mce)
Out[2]:
['styczen',
 'luty',
 'marzec',
 'kwiecien',
 'maj',
 'czerwiec',
 'lipiec',
 'sierpien',
 'wrzesien',
 'pazdziernik',
 'listopad',
 'grudzien']
Out[2]:
list

Funkcja wbudowana len() zwraca długość listy, czyli ilość elementów znajdujących się w liście. Lista może też być pusta, co oznacza że ma 0 elementów:

In [3]:
len(mce)
empty=[]
len(empty)
Out[3]:
12
Out[3]:
0

Odwołanie się do elemenów listy

Do elementów listy odwołujemy się poprzez index. Zapis [1] oznacza że wybieramy drugą pozycję listy. W języku programowania Python, tak jak w wielu językach typu C/C++/Java numerowanie pozycji zaczyna się od 0, nie od 1. Nie jest to na pierwszy rzut oka logiczne, ale niezbędne w wielu operacjach. W niektórych jęykach skryptowych np. R, numerowanie zaczynamy od 1, co pozornie jest logiczne ale powoduje wiele problemów.

Poniżej zestawiono pozycję poszczególnych elementów w liście. Zauważ, że do odwoływania się do poszczególnych elementów listy Python pozwala także stosować indeksy ujemne, które oznaczają numerację od końca listy:

sty lut mar kwi maj cze lip sie wrz paz lis gru
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]
[-12] [-11] [-10] [-9] [-8] [-7] [-6] [-5] [-4] [-3] [-2] [-1]

Należy podkreślić że w wielu językach - (znak minus) przy indeksie ma inne znaczenie. Na przykład w R oznacza "wszystkie elementy, za wyjątkiem tych z minusem"

Jeśli podamy indeks poza zakresem długości listy otrzymamy komunikat o błędzie: “IndexError: list index out of range”

Z listy można pobierać nie tylko pojedyncze elementy ale również wycinki,(ang. slice), poprzez określenie dwóch indeksów – początkowego i końcowego. Element oznaczany końcowym indeksem nie jest dołączany do wyciętej listy. Dlatego aby wybrać miesiące o indeksie 5,6,7,8 musimy podać mce[5:9]. Wtedy element na pozycji 8 zostanie wybrany, a na pozycji 9 nie. Jest to sposób postępowania typowy dla języków określanych jako 0-based, i może być nielogiczne dla osób przyzwyczajonych do rozwiązań 1-based, gdzie ostatni element zasięgu jest brany pod uwagę. Taka sytuacja występuje na przykład w R.

Wytniemy z listy mce nazwy miesięcy letnich (od 6 do 9) oraz przypiszemy je do nowej zmiennej o nazwie lato. Pamiętamy że indeksowanie rozpoczyna się od 0.

In [4]:
lato = mce[5:8] # zle
lato = mce[5:9] # dobrze

Gdy oba indeksy będą poza zakresem listy otrzymamy listę pustą. Listę pustą otrzymamy także, gdy pierwszy indeks będzie większy od drugiego. Jeśli lewy indeks wynosi 0, możemy go opuścić, wartość 0 jest domyślna. mce[:3] jest tym samym, co mce[0:3]. Jeżeli pominiemy pierwszy ostatni indeks zostanie zwórcona cześć do końca listy. Pominięcie obu indeksów zwróci całą listę.

In [5]:
mce[:3]
mce[9:]
mce[:]
Out[5]:
['styczen', 'luty', 'marzec']
Out[5]:
['pazdziernik', 'listopad', 'grudzien']
Out[5]:
['styczen',
 'luty',
 'marzec',
 'kwiecien',
 'maj',
 'czerwiec',
 'lipiec',
 'sierpien',
 'wrzesien',
 'pazdziernik',
 'listopad',
 'grudzien']

Operacje na listach

Lista jest obiektem, który można modyfikować (ang. mutable). Wyrażenie li[1] = 'd', oznacza, że chcemy elemetowi listy li na pozycji oznaczonej indeksem 1 przypisać nową wartość 'd'

In [6]:
li = ['a', 'b', 'c']
li
li[1]='d'
li
Out[6]:
['a', 'b', 'c']
Out[6]:
['a', 'd', 'c']

W przypadku list, podobnie jak w przypadku łańcuchów teksotwych, można używać operatora dodawania (+) oraz mnożenia (*). Pozostałe operatory matematyczne będą skutkowały błędem. Dodatkowo można stosować operator zawartości in

  • Operator dodawania łączy 2 listy w jedną listę, zawsze dodając drugą listę na końcu.
  • Operator mnożenia stosowany jest zawsze w połączeniu z liczbą. W wyniku takiej operacji elementy listy zostaną powtarzone określoną (przez liczbę) ilość razy.
In [7]:
li1 = ['a', 'b', 'c']
li2 = ['x', 'y', 'z']
li1 + li2
li1 *3
'b' in li1
'b' in li2
Out[7]:
['a', 'b', 'c', 'x', 'y', 'z']
Out[7]:
['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c']
Out[7]:
True
Out[7]:
False

Do obsługi list służy kilka funkcji wbudowanych. Na przykład

  • len() - długość listy
  • max() - alfabetycznie lub po wartościach
  • sorted() - sortowanie listy
In [8]:
len(mce)
max(mce) # najwyższa litera alfabetu
sorted(mce) # alfabetycznie
Out[8]:
12
Out[8]:
'wrzesien'
Out[8]:
['czerwiec',
 'grudzien',
 'kwiecien',
 'lipiec',
 'listopad',
 'luty',
 'maj',
 'marzec',
 'pazdziernik',
 'sierpien',
 'styczen',
 'wrzesien']

Krotki (tuplet)

Krotka (ang. tuple) jest niezmienną listą (ang. immutable). Zawartość krotki określamy tylko podczas jej tworzenia. Potem nie możemy już jej zmienić. Krotki definiujemy w identyczny sposób jak listę, lecz z jednym wyjątkiem -- zbiór elementów jest ograniczony w nawiasach okrągłych, zamiast w kwadratowych.

Zdefiniujmy krotkę o nazwie tydzien oraz przypiszemy jej poszczególne dni tygodnia

In [9]:
tydzien = ('poniedzialek', 'wtorek', 'sroda' , 'czwartek', 'piatek', 'sobota', 'niedziela') 
type(tydzien)
Out[9]:
tuple

Podobnie jak w przypadku listy, możemy określić długość krotki, odwoływać się do poszczególnych elementów ale nie możemy zmodyfikować zawartości krotki.

Do czego używa się krotki:

  • Krotki działają szybciej niż listy. Jeśli definiujemy stały zbiór wartości, który będzie używany tylko do iteracji, skorzystajmy z krotek zamiast z listy.
  • Jeśli chcielibyśmy używać danych "zabezpieczonych przed zapisem" (np. po to, żeby program był bezpieczniejszy), wykorzystajmy do tego krotki. Korzystając z krotek, zamiast z list, mamy pewność, że dane w nich zawarte nie zostaną nigdzie zmienione.
  • Krotki używane są do formatowania tekstu.
  • Krotki używamy do przekazywania argumentów do funkcji oraz przekazywania wyników działania funkcji

Słowniki (dictionary)

Słowniki to lista indeksowana kluczami a nie wartosciami całkowitymi. Kluczami mogą być dowolne modyfikowalne obiekty, najczęściej są to łańcuchy tekstowe. Słowniki są nieuporządkowanymi parami, dostęp do danych odbywa się poprzez klucze. Słownik definiuje się w nawiasach klamrowych jako pary klucz:wartość

In [10]:
dni = {'styczen':31,'luty':28,'marzec':31}
type(dni)
dni
dni['luty']
Out[10]:
dict
Out[10]:
{'luty': 28, 'marzec': 31, 'styczen': 31}
Out[10]:
28

W przypadku słowników dozwolone są operacje pobierania i dodawania wartości (poprzez parę klucz:wartość}. Można również pobierać klucze keys() oraz wartości values(), określać długość słownika. Klucze i wartości zwracane są w postaci list.

In [11]:
len(dni)
dni.keys()
Out[11]:
3
Out[11]:
dict_keys(['marzec', 'luty', 'styczen'])

Słowniki stosujemy w sytuacji, gdy dstęp do elementów listy lepiej realizować poprzez nazwy własne, na przykład do pól tabeli czy elementów, które są identyfikowane poprzez nieuporządkowane zbiory obiektów.

Struktury zagnieżdzone

Jak wspomniano elementem listy może być dowolny element zarówno typu prostego jak i złożonego. Oznacza to, że elementami listy, krotki albo słownika może też być lista, krotka albo słownik. Lista, której elementami są inne listy lub krotki nazywana jest listą zagnieżdzoną. Funkcja długości zwraca zawsze liczbę elementów najwyższego poziomu listy. Do kolejnych poziomów odwołujemy się poprzez kolejne indeksy, w kolejnych nawiasach kwadratowych.

In [12]:
li = ['a', 'X', 7, 11.0]
pop_dens = [['Azja', 246], ['Europa', 188],  
            ['Afryka', 87], ['AmerykaS', 57], 
            ['AmerykaN', 57], ['Australia', 8.3] , 
            ['Antarktyda', 0.00078]]
pop_dens
Out[12]:
[['Azja', 246],
 ['Europa', 188],
 ['Afryka', 87],
 ['AmerykaS', 57],
 ['AmerykaN', 57],
 ['Australia', 8.3],
 ['Antarktyda', 0.00078]]
In [13]:
pop_dens[1]
pop_dens[1][1]
Out[13]:
['Europa', 188]
Out[13]:
188

Note: funkcja zip

Funkcja zip() (ang. suwak) to jedna z ważniejszych funkcji do pracy na listach. Jej działanie przypomina zamek błyskawiczny. Zamienia dwie lub więcej list lub krotek o takiej samej długości w jedną listę zawierającą krotki. Lista jest takiej samej długości jak każda z list a każda krotka zawiera elementy ze każdej listy na tej samej pozycji i jest tej samej długości co liczba list.

[A,B,C] # [1,2,3] -> zip -> [A,1], [B,2], [C,3]

W naszym przykładzie mamy dwie listy, jedna zawiera nazwy miesięcy, druga zawiera liczbę dni. Funkcja zip przekształci te dwie listy w listę dwunastu krotek, każda o długości dwa, zawierających parę, miesiąc, liczba dni.

Należy zaznaczyć, że działanie funkcji zip() różni się w wersji 2.x i 3.x Pythona. W wersji 2.x zip() tworzy listę bezpośrednio, w wersji 3.x tworzy obiekt pośredni zwany iteratorem, aby wyświetlić strukturę listy należy zamienić go w listę w sposób jawny.

In [14]:
mce = ['styczen', 'luty', 'marzec', 'kwiecien', 'maj', 'czerwiec', 'lipiec', 'sierpien', 'wrzesien', 'pazdziernik', 'listopad', 'grudzien'] 
dny=[31,28,31,30,31,30,31,31,30,31,30,31]
x = zip(mce,dny)
x
list(x)
Out[14]:
<zip at 0x7fd2a00923c8>
Out[14]:
[('styczen', 31),
 ('luty', 28),
 ('marzec', 31),
 ('kwiecien', 30),
 ('maj', 31),
 ('czerwiec', 30),
 ('lipiec', 31),
 ('sierpien', 31),
 ('wrzesien', 30),
 ('pazdziernik', 31),
 ('listopad', 30),
 ('grudzien', 31)]

Funkcję zip można również wykorzystać do utworzenia słownika z dwóch list, która konwertuje dwie równoległe listy w listę list, gdzie każda lista to para rownoległych elementów z obu list.

In [15]:
dny=[31,28,31,30,31,30,31,31,30,31,30,31]
dni = dict(zip(mce,dny))
dni
Out[15]:
{'czerwiec': 30,
 'grudzien': 31,
 'kwiecien': 30,
 'lipiec': 31,
 'listopad': 30,
 'luty': 28,
 'maj': 31,
 'marzec': 31,
 'pazdziernik': 31,
 'sierpien': 31,
 'styczen': 31,
 'wrzesien': 30}

Ćwiczenie

  1. Połączyć zawartość zmiennych w jedną zmienną typu tekstowego. Na co należy zwrócić uwagę?
    n1='Liczba:'
    l1=12.6
    n2='jest liczbą zmiennoprzecinkową.'
    n3='Natomiast liczba:'
    l2=78
    n4='jest liczbą całkowitą'
    
  2. Dodać do siebie następujące liczby i wynik przechować w zmiennej: 16 i 31.4. Jakiego typu będzie zmienna wynikowa? Jak to sprawdzić?
  3. Podzielić przez siebie dwie liczby: 15 i 4, tak aby otrzymać liczbę całkowitą i resztę z dzielenia
  4. Utworzyć listę 5 elementów tekstowych
  5. Utworzyć słownik zawierający trzy wpisy określone kluczami: dzielna, dzielnik, wynik. Napisać równanie, które zmodyfikuje wartość klucza wynik na podstawie dzielenia pozostałych elementów słownika