Wstęp do programowaniaprac.im.pwr.wroc.pl/~szwabin/assets/intro/lectures/6.pdf · Wstęp do...
Transcript of Wstęp do programowaniaprac.im.pwr.wroc.pl/~szwabin/assets/intro/lectures/6.pdf · Wstęp do...
Wstęp do programowania
Wykład 6 Złożone typy danych
Janusz Szwabiński
Plan wykładu:
ListyKrotkiSłownikiZbiory
ListyListy to jeden z bardziej użytecznych typów danych w Pythonie. Podobnie jak łańcuch znaków, lista stanowisekwencję elementów. Różnica polega na tym, że jedna lista może zawierać elementy różnych typów.Najważniejsze własności tego typu:
służy do grupowania obiektówmoże przechowywać obiekty dowolnego typuelementy są indeksowaneprzypomina typ array w Perludynamiczny rozmiar rośnie w miarę dodawania elementówmoże być przedmiotem operacji wykrawania, sklejania i wielu innych
Istnieje kilka sposobów na stworzenie listy. Najprostszy z nich to użycie nawiasów kwadratowych:
In [1]:
lista = ["a",1.3,204,"Yoda"]
In [2]:
print(lista)
In [3]:
type(lista)
['a', 1.3, 204, 'Yoda']
Out[3]:
list
Help on list object:
class list(object) | list() -> new empty list | list(iterable) -> new list initialized from iterable's items | | Methods defined here: | | __add__(self, value, /) | Return self+value. | | __contains__(self, key, /) | Return key in self. | | __delitem__(self, key, /) | Delete self[key]. | | __eq__(self, value, /) | Return self==value. | | __ge__(self, value, /) | Return self>=value. | | __getattribute__(self, name, /) | Return getattr(self, name). | | __getitem__(...) | x.__getitem__(y) <==> x[y] | | __gt__(self, value, /) | Return self>value. | | __iadd__(self, value, /) | Implement self+=value. | | __imul__(self, value, /) | Implement self*=value. | | __init__(self, /, *args, **kwargs) | Initialize self. See help(type(self)) for accurate signature. | | __iter__(self, /) | Implement iter(self). | | __le__(self, value, /) | Return self<=value. | | __len__(self, /) | Return len(self). | | __lt__(self, value, /) | Return self<value. | | __mul__(self, value, /) | Return self*value.n | | __ne__(self, value, /) | Return self!=value. | | __new__(*args, **kwargs) from builtins.type
| Create and return a new object. See help(type) for accurate signature. | | __repr__(self, /) | Return repr(self). | | __reversed__(...) | L.__reversed__() -- return a reverse iterator over the list | | __rmul__(self, value, /) | Return self*value. | | __setitem__(self, key, value, /) | Set self[key] to value. | | __sizeof__(...) | L.__sizeof__() -- size of L in memory, in bytes | | append(...) | L.append(object) -> None -- append object to end | | clear(...) | L.clear() -> None -- remove all items from L | | copy(...) | L.copy() -> list -- a shallow copy of L | | count(...) | L.count(value) -> integer -- return number of occurrences of value | | extend(...) | L.extend(iterable) -> None -- extend list by appending elements from the iterable | | index(...) | L.index(value, [start, [stop]]) -> integer -- return first index of value. | Raises ValueError if the value is not present. | | insert(...) | L.insert(index, object) -- insert object before index | | pop(...) | L.pop([index]) -> item -- remove and return item at index (default last). | Raises IndexError if list is empty or index is out of range. | | remove(...) | L.remove(value) -> None -- remove first occurrence of value. | Raises ValueError if the value is not present. | | reverse(...) | L.reverse() -- reverse *IN PLACE* | | sort(...) | L.sort(key=None, reverse=False) -> None -- stable sort *IN PLACE* |
Długość i indeksowanie list
Długość listy (tzn. liczbę elementów) sprawdzimy znaną już funkcją len:
In [5]:
len(lista)
Pusta lista ma długość :
In [6]:
pusta_lista = []print(len(pusta_lista))
Elementy w liście są indeksowane od do :
In [7]:
print(lista[0])
In [8]:
print(lista[1])
In [9]:
print(lista[2])
In [10]:
print(lista[3])
0
0 n − 1
| ---------------------------------------------------------------------- | Data and other attributes defined here: | | __hash__ = None
Out[5]:
4
0
a
1.3
204
Yoda
In [11]:
print(lista[4]) #to powinno być wyjście poza zakres
Jeśli chodzi o indeksowanie, obowiązują zasady znane z łańcuchów znaków:
In [12]:
print(lista)
In [13]:
lista[-1] #ostatni element
In [14]:
lista[-2] #przedostatni
In [15]:
lista[:2] #dwa pierwsze
In [16]:
lista[2:] #od trzeciego do końca
In [17]:
lista[1:10] #w przypadku wycinków nie ma wyjścia poza zakres
---------------------------------------------------------------------------IndexError Traceback (most recent call last)<ipython-input-11-667d7b0b636b> in <module>()----> 1 print(lista[4]) #to powinno być wyjście poza zakres
IndexError: list index out of range
['a', 1.3, 204, 'Yoda']
Out[13]:
'Yoda'
Out[14]:
204
Out[15]:
['a', 1.3]
Out[16]:
[204, 'Yoda']
Out[17]:
[1.3, 204, 'Yoda']
Modyfikowanie list
Inaczej niż w przypadku łańcuchów znaków, poszczególne elementy list możemy zmieniać:
In [19]:
print(lista)
In [20]:
lista[3] = 'Chewie'
In [21]:
print(lista)
Możemy przy tym zmieniać całe wycinki:
In [22]:
lista [1:2] = ['Luke', 1024]
In [23]:
print(lista)
Zwróćmy uwagę, że w tym ostatnim przypadku zmienił się rozmiar listy:
In [24]:
len(lista)
Ponadto, gdybyśmy zamiast wycinka, podali indeks zmienianego elementu, otrzymalibyśmy listęzagnieżdżoną:
In [25]:
lista [1] = ['Luke', 1024]
In [26]:
print(lista)
Do elementów tej listy możemy dostać się przez podwójne indeksy:
['a', 1.3, 204, 'Yoda']
['a', 1.3, 204, 'Chewie']
['a', 'Luke', 1024, 204, 'Chewie']
Out[24]:
5
['a', ['Luke', 1024], 1024, 204, 'Chewie']
In [27]:
print(lista[1])
In [28]:
print(lista[1][1])
In [29]:
lista[1][1] = 'Han'
In [30]:
print(lista)
Operator in
Operatorem in możemy sprawdzać przynależność elementu do listy:
In [31]:
'Chewie' in lista
In [32]:
'Yoda' in lista
Uwaga na testy z listami zagnieżdżonymi:
In [33]:
'Han' in lista
In [34]:
'Han' in lista[1]
['Luke', 1024]
1024
['a', ['Luke', 'Han'], 1024, 204, 'Chewie']
Out[31]:
True
Out[32]:
False
Out[33]:
False
Out[34]:
True
Podstawowe operacje na listach
Listy możemy ze sobą sklejać przy pomocy operatora +:
In [35]:
lista = ["a",1.3,204,"Yoda"]druga_lista = ['Falcon', 3+2j]
In [36]:
lista + druga_lista
Operator * działa również tak samo, jak dla łańcuchów znaków:
In [38]:
print(3*lista)
Pętle po listach
Pętla for pozwala na iterowanie po elementach listy:
In [40]:
for element in lista: print(element)
Jeśli potrzebujemy pętli po indeksach elementów (jak w C/C++), bo np. chcemy zmodyfikować te elementy,wówczas musimy stworzyć listę indeksów i wykonywać pętlę po elementach tej listy. Służy do tego typ range:
Out[36]:
['a', 1.3, 204, 'Yoda', 'Falcon', (3+2j)]
['a', 1.3, 204, 'Yoda', 'a', 1.3, 204, 'Yoda', 'a', 1.3, 204, 'Yoda']
a1.3204Yoda
In [41]:
numbers = [1,2,3,4,5,6]print ('before: ', numbers)
for i in range(len(numbers)): # w ten sposób generuję listę indeksów listy numbers numbers[i] = 2*numbers[i] print('after: ', numbers)
Warto wiedzieć, że pętla po pustej liście nie wykona się ani razu:
In [44]:
for i in []: print("Ta instrukcja nie powinna się wykonać")
Dodawanie elementów do istniejącej listy
Omówione wcześniej przypisanie wycinkowi istniejącej listy innej z większą liczbą elementów niż ten wycinekto jeden ze sposobów na dodanie elementów do istniejącej już listy. Python oferuje kilka dodatkowych metod,które upraszczają tę operację:
In [45]:
lista = ['a','Luke',1024,204,'Chewie']
In [46]:
print(lista)
In [47]:
lista.append('Han') #dodajemy element na końcu listyprint(lista)
In [48]:
lista.insert(2,'Darth') #w określonym miejscuprint(lista)
In [49]:
lista.extend(['R2D2','C3P0']) #na końcu raz jeszczeprint(lista)
before: [1, 2, 3, 4, 5, 6]after: [2, 4, 6, 8, 10, 12]
['a', 'Luke', 1024, 204, 'Chewie']
['a', 'Luke', 1024, 204, 'Chewie', 'Han']
['a', 'Luke', 'Darth', 1024, 204, 'Chewie', 'Han']
['a', 'Luke', 'Darth', 1024, 204, 'Chewie', 'Han', 'R2D2', 'C3P0']
Uwaga! Metody append i extend nie są równoważne:
In [50]:
li = ['a','b','c']li.extend(['d','e','f'])print(li)print(len(li))print(li[-1])
In [51]:
li = ['a','b','c']li.append(['d','e','f'])print(li)print(len(li))print(li[-1])
Usuwanie elementów
In [52]:
print(lista)
In [53]:
lista.remove('Luke') #usuwamy konkretny element (jego pierwsze wystąpienie)print(lista)
In [52]:
lista.remove('Anakin')
['a', 'b', 'c', 'd', 'e', 'f']6f
['a', 'b', 'c', ['d', 'e', 'f']]4['d', 'e', 'f']
['a', 'Luke', 'Darth', 1024, 204, 'Chewie', 'Han', 'R2D2', 'C3P0']
['a', 'Darth', 1024, 204, 'Chewie', 'Han', 'R2D2', 'C3P0']
---------------------------------------------------------------------------ValueError Traceback (most recent call last)<ipython-input-52-dbb5be6900c1> in <module>()----> 1 lista.remove('Anakin')
ValueError: list.remove(x): x not in list
In [54]:
val = lista.pop() #usuwa ostatni element i zwraca jego wartośćprint(val)print(lista)
In [55]:
val = lista.pop(2) #jak wyżej, ale element o indeksie 2print(val)print(lista)
Inne możliwości:
In [56]:
del lista[0]print(lista)
In [57]:
lista[0:3] = []print(lista)
Przeszukiwanie list
In [58]:
lista = ['a','Luke',1024,204,'Chewie']
Szukamy indeksu konkretnego elementu (jego pierwszego wystąpienia):
In [59]:
lista.index('Luke')
In [60]:
lista.append('Luke')print(lista)
C3P0['a', 'Darth', 1024, 204, 'Chewie', 'Han', 'R2D2']
1024['a', 'Darth', 204, 'Chewie', 'Han', 'R2D2']
['Darth', 204, 'Chewie', 'Han', 'R2D2']
['Han', 'R2D2']
Out[59]:
1
['a', 'Luke', 1024, 204, 'Chewie', 'Luke']
In [61]:
lista.index('Luke')
In [62]:
lista.index('Luke',2)
In [63]:
lista.index('Yoda')
Ewentualnie możemy po prostu sprawdzić, czy element jest na liście:
In [64]:
'Yoda' in lista
In [65]:
'Yoda' not in lista
In [66]:
'Chewie' in lista
Inne przydatne metody
Zliczanie wystąpień:
Out[61]:
1
Out[62]:
5
---------------------------------------------------------------------------ValueError Traceback (most recent call last)<ipython-input-63-07e57c7162b5> in <module>()----> 1 lista.index('Yoda')
ValueError: 'Yoda' is not in list
Out[64]:
False
Out[65]:
True
Out[66]:
True
In [67]:
liczby = [10,21,33,11,24,11]liczby.count(11)
Sortowanie (tracimy oryginał!!!):
In [68]:
liczby.sort()print(liczby)
Odwrócenie porządku (również tracimy oryginał!!!):
In [69]:
liczby.reverse()print(liczby)
Wyższy stopień wtajemniczenia map, filter i (ewentualnie) reduce
Większość operacji, jakie można przeprowadzić na listach, daje się sprowadzić do trzech funkcji, któreznajdziemy w Pythonie:
map(funkcja,sekwencja) wywołuje funkcję funkcja dla każdego elementu listy wejściowej izwraca listę wynikówfilter(funkcja,sekwencja) zwraca sekwencję zawierającą te elementy z listy wejściowej,dla których wywołanie funkcja(element) zwróci wartość prawdziwąreduce(funkcja,sekwencja) zwraca pojedynczą wartość, która powstała w wynikuwywołania dwuparametrowej funkcji funkcja dla dwóch pierwszych elementów sekwencji, potemdla wyniku tego działania i następnego elementu sekwencji itd.
Należy przy tym wspomnieć, że w Pythonie 3.X reduce zostało usunięte z listy funkcji wbudowanych. Jest toczęściowo związane z faktem, że Guido van Rossum nigdy nie przepadał za tą funkcją:
"So now reduce(). This is actually the one I've always hated most, because, apart from a fewexamples involving + or *, almost every time I see a reduce() call with a nontrivial functionargument, I need to grab pen and paper to diagram what's actually being fed into thatfunction before I understand what the reduce() is supposed to do. So in my mind, theapplicability of reduce() is pretty much limited to associative operators, and in all other casesit's better to write out the accumulation loop explicitly." (artima.com, 10.03.2005)
Przykład szukamy liczb pierwszych w przedziale przy pomocy filter:⟨4, 25)
Out[67]:
2
[10, 11, 11, 21, 24, 33]
[33, 24, 21, 11, 11, 10]
In [72]:
def f(x): return x%2 != 0 and x%3 != 0 #prawda,jeśli niepodzielne przez 2 i 3
print(list(filter(f,range(4,25)))) #różnica w porównaniu z Pythonem 2.7!!!
To samo przy pomocy pętli:
In [73]:
pierwsze = []for liczba in range(4,25): if f(liczba): pierwsze.append(liczba) print(pierwsze)
Przykład obliczamy listę sześcianów przy pomocy map:
In [76]:
def cube(x): return x**3
list(map(cube,range(1,11)))
Przykład chcemy połączyć dwie listy w listę par przy pomocy map:
In [79]:
def sq(x): return x**2
liczby = range(4)list(map(sq,liczby))
Przykład chcemy obliczyć sumę sekwencji liczb w wykorzystaniem reduce:
[5, 7, 11, 13, 17, 19, 23]
[5, 7, 11, 13, 17, 19, 23]
Out[76]:
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
Out[79]:
[0, 1, 4, 9]
In [80]:
def add(x,y): return x+y
reduce(add,range(1,11))
In [81]:
import functools>>> functools.reduce(add,range(1,11))
Generowanie list (ang. list comprehensions)
Generowanie list to kolejny wygodny sposób na tworzenie nowych list z tych już istniejących:
In [83]:
lista = list(range(1,11))print(lista)
In [84]:
nowa_lista = [x for x in lista if x>5]print(nowa_lista)
In [85]:
[str(round(355/113.0,i)) for i in range(1,6)]
---------------------------------------------------------------------------NameError Traceback (most recent call last)<ipython-input-80-b8c55f93ce00> in <module>() 2 return x+y 3 ----> 4 reduce(add,range(1,11))
NameError: name 'reduce' is not defined
Out[81]:
55
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[6, 7, 8, 9, 10]
Out[85]:
['3.1', '3.14', '3.142', '3.1416', '3.14159']
In [86]:
l1 = [2,4,6]l2 = [4,3,-9][x*y for x in l1 for y in l2]
Listy i łańcuchy znaków
Aby przekształcić łańcuch znaków na listę znaków, korzystamy z funkcji list:
In [87]:
s = 'spam't = list(s)print(s)print(t)
Metoda split pozwala rozbić napis na listę słów:
In [88]:
s = 'pinning for the fjords't = s.split()print(t)
In [89]:
s = 'spam-spam-spam'delimiter = '-'s.split(delimiter)
Operacją odwrotną do split jest join:
In [90]:
t = ['pinning', 'for', 'the', 'fjords']delimiter = ':' #spacjadelimiter.join(t)
Out[86]:
[8, 6, -18, 16, 12, -36, 24, 18, -54]
spam['s', 'p', 'a', 'm']
['pinning', 'for', 'the', 'fjords']
Out[89]:
['spam', 'spam', 'spam']
Out[90]:
'pinning:for:the:fjords'
In [91]:
';'.join(t)
Ostrożnie z operacją przypisania
In [93]:
a = [1,2,3]b = aprint(b)
In [94]:
b[2] = 30
In [96]:
print(a)
Out[91]:
'pinning;for;the;fjords'
[1, 2, 3]
[1, 2, 30]
Aby wyjaśnić powyższy wynik, musimy wiedzieć nieco więcej na temat tego, jak Python traktuje zmienne, iczym to traktowanie różni się od innych języków, jak np. C/C++ czy Java.
Zmienne w C
Rozważmy najpierw następującą deklarację w C:
int a = 1;
W języku C deklaracja zmiennej powoduje stworzenie w pamięci operacyjnej komputera bloku, któryumożliwi przechowanie wartości przypisanej do tej zmiennej. Mówiąc bardziej obrazowo, zmienna w C (iwielu innych językach) to odpowiednio nazwane pudełko, do którego możemy wrzucać wartości oodpowiednim rozmiarze (typie):
a1
Jeżeli wykonamy operację przypisania
a = 2;
do pudełka wrzucona zostanie po prostu nowa wartość:
a2
Przyrównując starą zmienną do nowej,
int b = a
tworzymy nowe pudełko, do którego skopiowana zostanie zawartość pierwszego pudełka. Jednak w pamięcioperacyjnej będą to dwa różne obiekty:
a2
b2
Zmienne w Pythonie
W Pythonie w pamięci alokowana jest wartość. Operacja przypisania wartości do zmiennej
'a = 1'
może być interpretowana, jako przypięcie etykiety do wartości w pamięci komputera:
a1
Zmieniając wartość zmiennej,
a = 2
przenosimy etykietę do nowej wartości:
a21
Jeżeli okaże się, że stara wartość nie ma już żadnej etykiety (zmiennej odnoszącej się do niej), jestautomatycznie usuwana z pamięci.
Natomiast przypisując jedną zmienną do drugiej,
b = a
dodajemy nową etykietę do istniejącej wartości:
a2
b
In [97]:
a = 2
In [98]:
b = a
In [99]:
print(id(a))
In [100]:
print(id(b))
W przypadku niezmiennych typów danych (liczby, łańcuchy znaków, krotki) różnice między Pythonem a C sąpraktycznie niezauważalne. I rzeczywiście, jeżeli w powyższym przykładzie wartość b na inną, to nie będzieto miało żadnych konsekwencji dla a, ponieważ w pamięci komputera powstanie nowy obiekt z dołaczonąetykietą b. Wartość a nie zmieni się:
In [101]:
b = 3
In [102]:
print(a, id(a))
In [103]:
print(b, id(b))
W przypadku typów, które można zmieniać (listy i słowniki) jest inaczej:
10437248
10437248
2 10437248
3 10437280
In [104]:
a = [1,2,3]b = a
In [105]:
print(id(a), id(b))
In [106]:
b[2] = 'niespodzianka'
In [107]:
print(b)
In [108]:
print(a)
Chcąc stworzyć nową listę b, a nie tylko referencję do a, możemy użyć wycinków:
In [109]:
a = [1,2,3]
In [110]:
b = a[:]
In [111]:
print(a, id(a))
In [112]:
print(b, id(b))
In [113]:
b[2] = 'niespodzianka'print(b)
140400338702856 140400338702856
[1, 2, 'niespodzianka']
[1, 2, 'niespodzianka']
[1, 2, 3] 140400338704072
[1, 2, 3] 140400338696392
[1, 2, 'niespodzianka']
In [114]:
print(a)
KrotkiKrotki to kolejny sekwencyjny typ danych w Pythonie:
niezmienne listy (tzn. po utworzeniu nie można ich modyfikować)elementy dowolnego typuindeksowanieujemne indeksy i wycinkimożna je przeszukiwać, zliczać elementy itp.w przypadku iteracji po elementach szybsze niż listy
In [115]:
t = (12345, 5432, 'witaj', 'Yoda')print(type(t))print(t)
Nawiasy przy tworzeniu krotki możemy opuścić:
In [116]:
t1 = 12345, 5432, 'witaj', 'Yoda'print(type(t1))print(t1)t2 = 2,print(t2)
Indeksowanie działa w znajomy sposób:
In [117]:
t[-2]
[1, 2, 3]
<class 'tuple'>(12345, 5432, 'witaj', 'Yoda')
<class 'tuple'>(12345, 5432, 'witaj', 'Yoda')(2,)
Out[117]:
'witaj'
In [118]:
t[4]
In [119]:
t[1:3]
In [120]:
t[1:10]
Krotek rzeczywiście nie można modyfikować:
In [121]:
t.append('Chewie')
In [122]:
t.remove('witaj')
---------------------------------------------------------------------------IndexError Traceback (most recent call last)<ipython-input-118-302761d4dd84> in <module>()----> 1 t[4]
IndexError: tuple index out of range
Out[119]:
(5432, 'witaj')
Out[120]:
(5432, 'witaj', 'Yoda')
---------------------------------------------------------------------------AttributeError Traceback (most recent call last)<ipython-input-121-27800945c026> in <module>()----> 1 t.append('Chewie')
AttributeError: 'tuple' object has no attribute 'append'
---------------------------------------------------------------------------AttributeError Traceback (most recent call last)<ipython-input-122-0b91c7db4d76> in <module>()----> 1 t.remove('witaj')
AttributeError: 'tuple' object has no attribute 'remove'
In [123]:
t[1] = 'Luke'
Działają tylko niektóre metody znane z list:
In [124]:
t = 1,2,3,4,5,6
In [125]:
t.index(6)
In [126]:
t.count(3)
In [127]:
t.sort()
---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-123-d8d86ca30d95> in <module>()----> 1 t[1] = 'Luke'
TypeError: 'tuple' object does not support item assignment
Out[125]:
5
Out[126]:
1
---------------------------------------------------------------------------AttributeError Traceback (most recent call last)<ipython-input-127-0708f4171c7e> in <module>()----> 1 t.sort()
AttributeError: 'tuple' object has no attribute 'sort'
In [128]:
t.reverse()
Przynależność elementów sprawdzamy jak w przypadku list:
In [129]:
t = (12345, 5432, 'witaj', 'Yoda')
In [130]:
'Yoda' in t
In [131]:
'Luke' in t
Krotki i przypisania
In [132]:
print(t)a,b,c, d = tprint(a)print(b)print(c)print(d)
---------------------------------------------------------------------------AttributeError Traceback (most recent call last)<ipython-input-128-6c6d67d96efe> in <module>()----> 1 t.reverse()
AttributeError: 'tuple' object has no attribute 'reverse'
Out[130]:
True
Out[131]:
False
(12345, 5432, 'witaj', 'Yoda')123455432witajYoda
In [133]:
a = 10b = 2a, b = b, aprint(a)print(b)
Krotki i łańcuchy znaków
In [134]:
s = 'spam't = tuple(s)print(t)
In [135]:
''.join(t)
Krotki i listy
Funkcje tuple i list pozwalają konwertować jeden typ w drugi:
In [136]:
t = (1,2,3,4)
In [138]:
l = list(t)print(l)
In [139]:
t2 = tuple(l)print(t2)
Ponadto, funkcja zip pozwala utworzyć z dwóch sekwencji generator listy krotek, z których każda zawierapo jednym elemencie z każdej sekwencji:
210
('s', 'p', 'a', 'm')
Out[135]:
'spam'
[1, 2, 3, 4]
(1, 2, 3, 4)
In [142]:
s = 'abcd't = 1,2,3,4zip(s,t)
In [143]:
list(zip(s,t))
Przy tym, jeśli sekwencje są różnych długości, wynikowa lista będzie miała długość krótszej z nich:
In [144]:
s1 = 'abc's2 = 'ABCD'list(zip(s1,s2))
Krotki i pętle
Funkcji zip oraz rozpakowywania krotek używa się często w pętlach for, aby iterować po elementachdwóch sekwencji jednocześnie:
In [146]:
s = 'abcd't = 1,2,3,4for litera, cyfra in zip(s,t): print(litera, cyfra)
Równie przydatna jest funkcja enumerate, która zwraca (na żądanie) pary (indeks,element) danejsekwencji (nie tylko krotki):
In [149]:
enumerate(s)
Out[142]:
<zip at 0x7fb1805118c8>
Out[143]:
[('a', 1), ('b', 2), ('c', 3), ('d', 4)]
Out[144]:
[('a', 'A'), ('b', 'B'), ('c', 'C')]
a 1b 2c 3d 4
Out[149]:
<enumerate at 0x7fb1804e96c0>
In [150]:
for index, element in enumerate(s): print(index, element)
Porównywanie krotek
Krotki, podobnie jak inne sekwencje, można ze sobą porównywać. Python porównuje ze sobą pierwszeelementy krotek, jeżeli są one równe, to drugie i tak aż do znalezienia różnicy. Po jej znalezieniuporównywanie zostaje przerwane:
In [151]:
(0,1,2) < (0,0,4)
In [152]:
(0,1,2) < (0,2,0)
SłownikiSłowniki to w pewnym sensie uogólnienia list. W listach indeksami są liczby całkowite, w przypadkusłowników mogą to być również inne typy. Najważniejsze własności tego typu danych:
definiują relację do między zbiorem kluczy a zbiorem wartościtablice asocjacyjne, odpowiadają typowi hash w Perlu lub instancji klasy Hashtable w Javiewartości mogą być dowolnego typukluczami mogą być łańcuchy znaków, liczby oraz krotki, o ile tylko nie zawierają elementów, któremogą być modyfikowalneklucze muszą być unikalneparę (klucz,wartość) można dodać lub usunąć w dowolnej chwilipary (klucz,wartość) w słowniku nie są uporządkowane
Deklaracja i dostęp do zawartości
In [154]:
tel = {'Yoda' : 1234, 'Chewie' : 5678, 'Luke' : 9002}print(tel)
1 1
0 a1 b2 c3 d
Out[151]:
False
Out[152]:
True
{'Chewie': 5678, 'Luke': 9002, 'Yoda': 1234}
In [155]:
tel2 = dict(Han=1111, R2D2=2222, C3P0=3333)print(tel2)
Do wartości odnosimy się przez klucz:
In [156]:
tel['Yoda']
Jednak przez wartość nie możemy odnieść się do klucza:
In [157]:
tel[1234]
Błąd ten oznacza, że podaliśmy klucz, który nie istnieje. Czasami sytuacja taka może pojawić się wprogramie. Wówczas mamy trzy możliwości:
pojawi się wyjątek (o tym już niedługo) i interpreter przerwie działanie programu, jak powyżejpojawi się wyjątek, ale program wyłapie ten wyjątek, odpowiednio zareaguje i będzie kontynuowałpracę (o tym też już wkrótce)program będzie po prostu działał, ponieważ odczytaliśmy wartość ze słownika w bezpieczny sposób
In [158]:
tel.get('Yoda','not found')
In [159]:
tel.get('Darth','not found')
Wartości w słowniku można zmieniać:
{'Han': 1111, 'C3P0': 3333, 'R2D2': 2222}
Out[156]:
1234
---------------------------------------------------------------------------KeyError Traceback (most recent call last)<ipython-input-157-399835b518f5> in <module>()----> 1 tel[1234]
KeyError: 1234
Out[158]:
1234
Out[159]:
'not found'
In [160]:
tel['Yoda'] = 1111print(tel)
Podobnie dodajemy nowe wartości:
In [161]:
tel['Lando'] = 9999print(tel)
Można również w ten sposób:
In [162]:
tel.update(tel2)print(tel)
Lista kluczy, wartości i par
In [163]:
tel.keys()
In [164]:
tel.values()
In [165]:
tel.items()
Kopiowanie słowników
{'Chewie': 5678, 'Luke': 9002, 'Yoda': 1111}
{'Chewie': 5678, 'Lando': 9999, 'Luke': 9002, 'Yoda': 1111}
{'Lando': 9999, 'Han': 1111, 'Luke': 9002, 'Chewie': 5678, 'R2D2': 2222, 'C3P0': 3333, 'Yoda': 1111}
Out[163]:
dict_keys(['Lando', 'Han', 'Luke', 'Chewie', 'R2D2', 'C3P0', 'Yoda'])
Out[164]:
dict_values([9999, 1111, 9002, 5678, 2222, 3333, 1111])
Out[165]:
dict_items([('Lando', 9999), ('Han', 1111), ('Luke', 9002), ('Chewie', 5678), ('R2D2', 2222), ('C3P0', 3333), ('Yoda', 1111)])
In [167]:
backup = tel.copy()print(backup)
Uwaga! Podobnie jak w przypadku list, operator przypisania nie tworzy nowego obiektu:
In [168]:
d1 = dict(a=1,b=2,c=3)
In [169]:
d2 = d1print(d1)print(d2)
In [170]:
d2['c'] = 100print(d2)print(d1) #oryginał też został zmieniony!!!
In [171]:
d1 = dict(a=1,b=2,c=3)d2 = d1.copy()d2['c'] = 100print(d2)print(d1)
Usuwanie elementów
In [172]:
print(tel)
Wybrany element:
{'Lando': 9999, 'Han': 1111, 'Luke': 9002, 'Chewie': 5678, 'R2D2': 2222, 'C3P0': 3333, 'Yoda': 1111}
{'c': 3, 'b': 2, 'a': 1}{'c': 3, 'b': 2, 'a': 1}
{'c': 100, 'b': 2, 'a': 1}{'c': 100, 'b': 2, 'a': 1}
{'c': 100, 'a': 1, 'b': 2}{'c': 3, 'b': 2, 'a': 1}
{'Lando': 9999, 'Han': 1111, 'Luke': 9002, 'Chewie': 5678, 'R2D2': 2222, 'C3P0': 3333, 'Yoda': 1111}
In [173]:
del tel['Han']print(tel)
Wybrany element, jednocześnie zwracając jego wartość:
In [174]:
val = tel.pop('Chewie')print(val)print(tel)
Wszystkie elementy na raz:
In [175]:
tel.clear()print(tel)
Słowniki i pętle
In [176]:
tel = backup.copy()print(tel)
Najprostsza pętla for po elementach słownika oznacza po prostu pętlę po jego kluczach:
In [177]:
for item in tel: print(item)
Jeśli chcemy iterować jednocześnie po parze (klucz,wartość), wykorzystujemy następującą metodę:
{'Lando': 9999, 'Luke': 9002, 'Chewie': 5678, 'R2D2': 2222, 'C3P0': 3333, 'Yoda': 1111}
5678{'Lando': 9999, 'Luke': 9002, 'R2D2': 2222, 'C3P0': 3333, 'Yoda': 1111}
{}
{'Lando': 9999, 'Han': 1111, 'Luke': 9002, 'Chewie': 5678, 'R2D2': 2222, 'C3P0': 3333, 'Yoda': 1111}
LandoHanLukeChewieR2D2C3P0Yoda
In [179]:
for key, val in iter(tel.items()): print(key, val)
W Pythonie 2.7 podobną funkcjonalność miała metoda iteritems.
Sortowanie słowników
Ogólnie słownik jest sekwencją nieuporządkowaną, co oznacza, że klucze i odpowiadające im wartościpojawiają się w pętli w przypadkowym porządku. Zawsze możemy jednak iterować po posortowanej liściekluczy:
In [180]:
for key in sorted(tel.keys()): print(key,tel[key])
Należy jednak pamiętać, że w ten sposób nie posortowaliśmy samego słownika, a raczej stworzyliśmy jegoreprezentację, która jest posortowana po kluczach.
Skoro już jesteśmy przy funkcji sorted, to oferuje ona również możliwość sortowania po wartościach:
In [181]:
for k in sorted(tel, key=tel.get, reverse=True): print(k, tel[k])
Lando 9999Han 1111Luke 9002Chewie 5678R2D2 2222C3P0 3333Yoda 1111
C3P0 3333Chewie 5678Han 1111Lando 9999Luke 9002R2D2 2222Yoda 1111
Lando 9999Luke 9002Chewie 5678C3P0 3333R2D2 2222Han 1111Yoda 1111
In [182]:
for k in sorted(tel, key=tel.get): print(k, tel[k])
Zbiory
Zbiór to nieuporządkowana kolekcja unikalnych elementów.
Deklaracja
In [183]:
z1 = set('abracadabra')print(z1)z2 = set('alacazam')print(z2)
Zwróćmy uwagę, że w wynikowych zbiorach nie ma powtórzeń. Dlatego ich podstawowe zastosowanie tousuwanie powtórzeń z innych sekwencji:
In [184]:
liczby = [1,2,3,4,5,4,3,3,6,5,1]zbior = set(liczby)print(zbior)unikalne_liczby = list(zbior)print(unikalne_liczby)
Operacje na zbiorach
Różnica zbiorów to elementy, które należą do jednego zbioru, i nie należą do drugiego:
Han 1111Yoda 1111R2D2 2222C3P0 3333Chewie 5678Luke 9002Lando 9999
{'d', 'c', 'r', 'a', 'b'}{'m', 'c', 'z', 'a', 'l'}
{1, 2, 3, 4, 5, 6}[1, 2, 3, 4, 5, 6]
In [185]:
print(z1)print(z2)z1 - z2
Suma zbiorów to wszystkie elementy, które należą albo do jednego albo do drugiego zbioru:
In [186]:
z1 | z2
Iloczyn zbiorów to ich część wspólna:
In [187]:
z1 & z2
Python posiada również operator sumy poprzecznej elementy, które należą do z1 lub z2, ale nie należą doich części wspólnej:
In [188]:
z1 ̂ z2
In [189]:
(z1 | z2) - (z1 & z2)
{'d', 'c', 'r', 'a', 'b'}{'m', 'c', 'z', 'a', 'l'}
Out[185]:
{'b', 'd', 'r'}
Out[186]:
{'a', 'b', 'c', 'd', 'l', 'm', 'r', 'z'}
Out[187]:
{'a', 'c'}
Out[188]:
{'b', 'd', 'l', 'm', 'r', 'z'}
Out[189]:
{'b', 'd', 'l', 'm', 'r', 'z'}