Języki skryptowe - Python¶
Wykład 2¶
- sekwencyjne typy danych
- system binarny i szesnastkowy
- wyrażenia logiczne
Ostatnio¶
- wprowadzone zostały 4 typy zmiennych: int, float, complex i str
# [zmienna] [operator przypisania] [wartość] # typowanie dynamiczne n = 10 # liczba całkowita x = 1.5 # liczba zmiennoprzecinkowa c = 2j # liczba zespolona s = "Python" # łańcuch znaków
Łańuch znaków¶
- zmienna str przechowuje tak naprawdę ciąg znaków
- w którym każdy znak ma określoną pozycję
s = "Python" s[0] # str[i] -> i-ty znak w ciągu
'P'
s[1] # pierwszy to drugi?
'y'
s[2]
't'
Indeksowanie¶
- indeksowanie zaczyna się od 0 a kończy na n-1, gdzie n - długość ciągu
s = "Python" n = len(s) # długość łańcucha s print(n)
6
s[n-1] # ostatni element
'n'
s[n] # poza zakresem
--------------------------------------------------------------------------- IndexError Traceback (most recent call last) <ipython-input-7-1dea7ae0782c> in <module>() ----> 1 s[n] # poza zakresem IndexError: string index out of range
Wycinki¶
s = "Python" s[2:4] # elementy od 2 do 3 (czyli "od 3 do 4")
'th'
s[2:] # od indeksu 2 do końca
'thon'
s[:2] # od początku do 1
'Py'
s[2:1000] # nie ma błędu o wyjściu poza zakres
'thon'
Wycinki z krokiem¶
s = "0123456789" s[2:8:2] # sekwencja[początek:koniec:krok]
'246'
s[2::3] # od 2 do końca co 3
'258'
s[::2] # od początu do końca co 2
'02468'
Indeksy ujemne¶
- indeks \(-k\) oznacza \(n-k\), gdzie \(n\) - długość łańcucha
s = "Python" s[-1] # 6 - 1 = 5 -> ostatni znak
'n'
s[-2] # 6 - 2 = 4 -> przedostatni
'o'
s[-2:] # od 4 do końca -> dwa ostatnie
'on'
s[:-2] # wszystko oprócz dwóch ostatnich
'Pyth'
Dygresja o klasach¶
- więcej o klasach będzie na dalszych wykładach
- klasa definuje obiekt
- przypisując wartość zmiennej tworzymy obiekt danej klasy
n = 10 # tworzymy obiekt klasy int
Dygresja o klasach¶
- klasa może posiadać zmienne i metody (czyli funkcje działające na obiekt)
x = 1.0 # tworzymy obiekt klasy float # metody/zmienne klasy wywołujemy . x.is_integer() # [obiekt].metoda
True
s = "Python" # tworzymy obiekt klasy str s.replace('yt', 'yyyyyt') # [obiekt].metoda
'Pyyyyython'
Lista (list)¶
- sekwencja zmiennych dowolnego typu
- dynamiczny rozmiar
- inicjowana jest:
- nawiasy kwadratowe
- jawnie list([iterable]) (czyli konstruktor klasy list)
- lista składana (list comprehension)
Lista przez [ ]¶
lista = [1, 2, 'a', "Python"]
len(lista) # długość listy
4
lista[0] # pierwszy element listy
1
lista[-1] # ostatni element listy
'Python'
Lista przez konstruktor¶
lista = list([1,2,3]) # bez sensu, ale można print(lista)
[1, 2, 3]
lista = list("Python") # można stworzyć listę ze string print(lista)
['P', 'y', 't', 'h', 'o', 'n']
lista = list(1) # ale już nie z int
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-28-5b92e1b521a9> in <module>() ----> 1 lista = list(1) # ale już nie z int TypeError: 'int' object is not iterable
Lista składana¶
cyfry = ["jeden", "dwa", "trzy"] # definiujemy listę # [wartość] dla [obiektu] z [listy] # pętle zostaną szerzej omówione na kolejnych wykładach dlugosc = [len(cyfra) for cyfra in cyfry] print(dlugosc)
[5, 3, 4]
cyfry = ["jeden", "dwa", "trzy"] # definiujemy listę # [wartość] dla [obiektu] z [listy] jeśli [warunek] # warunki zostaną szerzej omówione pod koniec wykładu dlugosc = [len(cyfra) for cyfra in cyfry if cyfra != 'dwa'] print(dlugosc)
[5, 4]
Lista jako rezultat funkcji¶
help(str.split)
Help on method_descriptor: split(...) S.split(sep=None, maxsplit=-1) -> list of strings Return a list of the words in S, using sep as the delimiter string. If maxsplit is given, at most maxsplit splits are done. If sep is not specified or is None, any whitespace string is a separator and empty strings are removed from the result.
("Python is awesome, fast, and friendly!").split()
['Python', 'is', 'awesome,', 'fast,', 'and', 'friendly!']
("Python is awesome, fast, and friendly!").split(',')
['Python is awesome', ' fast', ' and friendly!']
Krotka (tuple)¶
- sekwencja zmiennych dowolnego typu
- stały rozmiar
- inicjowana jest:
- nawiasy okrągłe
- ciąg elementów oddzielonych przecinkiem
- jawnie tuple([iterable])
Krotka¶
krotka = (1, 2, 3, "Python") # jak lista, ale () zamiast [] print(krotka)
(1, 2, 3, 'Python')
krotka = 1, 2, 3, "Python" # brak nawiasów = tuple print(krotka)
(1, 2, 3, 'Python')
lista = list("Python") # lista ze stringa krotka = tuple(lista) # krotka z listy print(lista) print(krotka)
['P', 'y', 't', 'h', 'o', 'n'] ('P', 'y', 't', 'h', 'o', 'n')
Lista vs Krotka¶
- krotka ma stały rozmiar a lista jest dynamiczna
- krotka jest "niezmienna" (immutable) w przeciwieństwie do listy (mutable)
- więcej o mutable vs immutable w dalszej części wykładu
- jeśli sekwencja obiektów jest stała w czasie działania programu, lepiej używać krotek
- szybsze
- bezpieczniejsze
- mogą być kluczami w słowniku (o słownikach na kolejnych wykładach)
Lista vs Krotka¶
lista = [1, 2, 3] print(lista) lista[0] = 2 print(lista)
[1, 2, 3] [2, 2, 3]
krotka = (1, 2, 3) krotka[0] = 2
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-38-9a057d2d95b0> in <module>() 1 krotka = (1, 2, 3) 2 ----> 3 krotka[0] = 2 TypeError: 'tuple' object does not support item assignment
Range¶
- uwaga: w Pythonie 2 range() jest funkcją wbudowaną; w Pythonie 3 jest to typ danych (klasa)
- reprezentuje (niezmienniczą) sekwencję liczb
- zajmuje mniej pamięci niż list lub tuple (przechowuje tylko informację o początku, końcu i kroku)
Range¶
x = range(10) # od 0 do 10 print(x) # w Pythonie 2 zobaczylibyśmy [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
range(0, 10)
print(list(x)) # zrzutujemy na listę, żeby wydrukować
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
x[0] = 1 # range jest immutable
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-41-3a9de573c036> in <module>() ----> 1 x[0] = 1 # range jest immutable TypeError: 'range' object does not support item assignment
Range¶
cyfry = range(0, 10) # range(początek = 0, koniec) parzyste = range(2, 10, 2) # range(początek, koniec, krok) nieparzyste = range(1, 10, 2) print(list(cyfry)) print(list(parzyste)) print(list(nieparzyste))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [2, 4, 6, 8] [1, 3, 5, 7, 9]
Sekwencyjne typy danych¶
- list - dynamiczny ciąg zmiennych dowolnego typu
- tuple - niezmienniczy ciąg zmiennych dowolnego typu
- range - niezmienniczy ciąg liczba całkowitych
- str - niezmienniczy ciąg znaków
- (dla kompletności) są jeszcze binarne sekwencyjne typy danych: bytes, bytearray, memoryview
Operacje na sekwencjach¶
- in - prawda jeśli element należy do sekwencji, inaczej fałsz
- not in - fałsz jeśli element należy do sekwencji, inaczej prawda
s = "Python" "y" in s
True
"p" not in s
True
- więcej o prawdzie i fałszu w dalszej części wykładu
Operacje na sekwencjach¶
- splot (concatenation)
- nie dla range
begin = "Python " middle = "is " end = "awesome!" begin + middle + end
'Python is awesome!'
lista = [1, 2, 3, 4] dodatek = [5, 6, 7, 8] dodatek + lista # kolejność ma znaczenie
[5, 6, 7, 8, 1, 2, 3, 4]
Operacje na sekwencjach¶
- mnożenie przez liczbę calkowitą
- nie dla range
znak = '-' znak * 10
'----------'
krotka = (1, 2, 3) 2 * krotka
(1, 2, 3, 1, 2, 3)
Operacje na sekwencjach¶
- wycinki
lista = [1, 2, 3, "Python"] lista[:2] # dwa pierwsze
[1, 2]
lista[3][-2:] # dwa ostatnie ostatniego
'on'
range(3, 15, 3)[:2] # dla range też działa
range(3, 9, 3)
Funkcje wbudowane dla sekwencji¶
- len - długość sekwencji
- min, max - najmniejszy, największy element
len([1,2,-3]) # liczba elementów
3
min([1,2,-3]) # minimum
-3
max("Python") # maximum
'y'
Wspólne funkcje klasowe sekwencji¶
- index - indeks pierwszego znalezionego elementu
- count - ilość wystąpień elementu
x = [1, 2, 3, 4, 5] * 2 print(x)
[1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
x.count(4) # liczba 4 pojawia się 2 razy
2
x.index(4) # pierwszy raz dla i=3
3
Operacje na sekwencjach "zmiennych" (mutable)¶
- na razie znamy: list
- ale na kolejnych wykładach poznamy kolejne
- sekwencje "niezmienne" (immutable): tuple, range i str
- ale na kolejnych wykładach poznamy kolejne
- więcej o mutable vs immutable w dalszej części wykładu
Operacje na sekwencjach "zmiennych" (mutable)¶
lista = [1, 2, 3] lista[1] = 4 # zamień wartość drugiego elementu print(lista)
[1, 4, 3]
lista = [1, 2, 3] lista[1:2] = [5, 5] # zamień wycinek print(lista)
[1, 5, 5, 3]
Operacje na sekwencjach "zmiennych" (mutable)¶
lista = [1, 2, 3] del lista[1:2] # usuń wycinek print(lista)
[1, 3]
lista = list(range(10)) del lista[::2] # usuń co drugi element print(lista)
[1, 3, 5, 7, 9]
Funkcje klasowe sekwencji "zmiennych" (mutable)¶
lista = [1, 2, 3, 4, 5] lista.append(6) # append dodaje element na koniec listy print(lista) lista.append([7, 8, 9]) # lista dodana jako element print(lista)
[1, 2, 3, 4, 5, 6] [1, 2, 3, 4, 5, 6, [7, 8, 9]]
lista = [1, 2, 3, 4, 5] lista.extend([6, 7, 8, 9]) # extend rozwija listę print(lista)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Funkcje klasowe sekwencji "zmiennych" (mutable)¶
lista = [1, 2, 3] lista.clear() # usuwa wszystkie elementy print(lista)
[]
lista = [1, 2, 3] kopia = lista.copy() # kopiuje całą listę print(kopia)
[1, 2, 3]
Funkcje klasowe sekwencji "zmiennych" (mutable)¶
lista = [1, 2, 3] lista.insert(1, 4) # wstaw 4 pod indeks 2 print(lista)
[1, 4, 2, 3]
lista = [1, 2, 3] lista.pop(1) # zwróć i usuń *i*-ty element
2
print(lista)
[1, 3]
Funkcje klasowe sekwencji "zmiennych" (mutable)¶
lista = ['a', 'b', 3] * 3 print(lista) lista.remove('b') # usuń element (pierwsze wystąpienie) print(lista)
['a', 'b', 3, 'a', 'b', 3, 'a', 'b', 3] ['a', 3, 'a', 'b', 3, 'a', 'b', 3]
lista = [1, 2, 3] lista.reverse() # odwróć kolejność print(lista)
[3, 2, 1]
Funkcja sort - tylko dla list¶
help(list.sort)
Help on method_descriptor: sort(...) L.sort(key=None, reverse=False) -> None -- stable sort *IN PLACE*
lista = ['e', 'D', 'a', 'b', 'C'] lista.sort() # sortuj print(lista) lista.sort(key=str.lower) # sortuj wg funkcji key print(lista)
['C', 'D', 'a', 'b', 'e'] ['a', 'b', 'C', 'D', 'e']
System dziesiętny¶
-
ogólnie: \(\(a_n...a_2a_1a_0 = \sum\limits_{i = 0}^{n} a_i \cdot 10^{i} \text{ , gdzie } a_i \in \{0,...,9\}\)\)
-
np. \(\(438 = 4 \cdot 10^2 + 3 \cdot 10^1 + 8 \cdot 10^0\)\)
- przykład zastosowania: warzywniak
System dwójkowy (binarny)¶
-
ogólnie: \(\(a_n...a_2a_1a_0 = \sum\limits_{i = 0}^n a_i \cdot 2^i \text{ , gdzie } a_i \in \{0,1\}\)\)
-
np. \(\(110110110_2 = 1 \cdot 2^8 + 1 \cdot 2^7 + 0 \cdot 2^6 + 1 \cdot 2^5 + 1 \cdot 2^4 + 0 \cdot 2^3 + 1 \cdot 2^2 + 1 \cdot 2^1 + 0 \cdot 2^0 = 256 + 128 + 32 + 16 + 4 + 2 = 438\)\)
- przykład zastosowania: elektronika cyfrowa
Bit (binary digit) i bajt (byte)¶
- dwa równie prawdopodobne stany: \(\{0, 1\}\)
- 1B = 8b (1 bajt = 8 bitów)
- myląca konwencja informatyków:
- 1KB = 1024B
- 1MB = 1024KB = 1024 * 1024B = 1048576B
- 1GB = 1024MB = 1073741824B
- przedrostki binarne: kibi, mebi, gibi... nie do końca się przyjęły
Zmienne w pamięci operacyjnej¶
- każda zmienna przechowywana jest w pamięci operacyjnej w postaci bitowej
- przy czym bajt jest najmniejszym adresowalnym "fragmentem" pamięci
- np. \(438 = 110110110_2\) zajmie co najmniej 2B = 16b (a nie 9 bitów)
from graphviz import Source pamiec = Source('digraph "pamiec" \ { rankdir=LR; node [shape="box"; fontsize=40;]; splines=none; \ "0000001" -> "10110110"}')
pamiec
Int (long int) w C++¶
- zajmuje 32 bity
- stąd 438 = 00000000 00000000 00000001 10110110
- bez znaku: \((0, 2^{32} - 1) = (0, 4294967295)\)
- ze znakiem: \((-2^{31} - 1, 2^{31} - 1) = (-2147483647, 2147483647)\)
- w C++ występują również: char (8 bitów), short int (8 bitów), long long int (64 bity)
Czas uniksowy¶
- liczba sekund od epoki Uniksa (01.01.1970 UTC)
- 32-bitowa liczba ze znakiem
- 2147483647 sekund minie 19 stycznia 2038 o godz. 03:14:07 UTC
- ciekawostka: iPhone 1970 bug
Manually changing the date to May 1970 or earlier can prevent your iOS device from turning on after a restart.
Limit pamięci¶
- Architektura 32-bitowa dysponuje \(2^{32}\) adresami
B = 1 # bajt KB = 1024 * B # kilobajt MB = 1024 * KB # megabajt 2**32 / MB
4096.0
- stąd limit pamięci operacyjnej w systemach 32-bitowych to ok. 4GB
- co często daje limit na pamięć RAM rzędu 3GB (bo karta graficzna)
Int w Pythonie¶
# zwróć uwagę na sposób importowania: # from [moduł] import [funkcja] as [nazwa] from sys import getsizeof as rozmiar help(rozmiar)
Help on built-in function getsizeof in module sys: getsizeof(...) getsizeof(object, default) -> int Return the size of object in bytes.
rozmiar(0)
24
rozmiar(2**100)
40
System szesnastkowy (heksadecymalny)¶
-
ogólnie: \(\(a_n...a_2a_1a_0 = \sum\limits_{i = 0}^n a_i \cdot 16^i \text{ , gdzie } a_i \in \{0,...,9,A,...,F\}\)\)
-
np. \(\(1\text{b}6_{16} = 1 \cdot 16^2 + 11 \cdot 16^1 + 6 \cdot 16^0 = 256 + 176 + 6 = 438\)\)
- przykład zastosowania: adres MAC (Media Access Control), grafika komputerowa (kolory RGB)
Kolory RGB¶
- w 24-bitowym RGB:
- czerwony: 0 - 255
- zielony: 0 - 255
- niebieski: 0 - 255
- czemu do 255? 1 bajt = 8 bitów
- w 32-bitowym dochodzi kanał alpha (przezroczystość)
Kolory RGB¶
- często spotka się zapis:
#RRGGBB
- gdzie
RR
- kolor czerwony w zapisie szesnastkowym itd. - np.
#ff96cb
- czerwony: \(\text{ff}_{16} = 255\)
- zielony: \(96_{16} = 150\)
- niebieski: \(\text{cb}_{16} = 203\)
Kolory RGB¶
# rysuj bezpośrednio w Jupyter %matplotlib inline import matplotlib.pyplot as plt import matplotlib.patches as patches # zdefiniuj kwadrat kwadrat = patches.Rectangle( (0.0, 0.0), # wierzchołek 1.0, # szerokość 1.0, # wysokość facecolor="#ff96cb" # kolor wypełnienia ) plt.figure(figsize=(1,1)) # rozmiar plt.axis('off') # wyłącz osie # narysuj kwadrat; gca -> get currect axis plt.gca().add_patch(kwadrat)
<matplotlib.patches.Rectangle at 0x7ff3e862cdd8>
Systemy liczbowe w Pythonie¶
bin(438) # liczba 438 w systemie binarnym
'0b110110110'
0b110110110 # 0b sygnalizuje system binarny
438
0b0000000000110110110 # wiodące zera nic nie zmieniają
438
hex(438) # liczba 438 w systemie heksadecymalnym
'0x1b6'
0x1b6 # 0x sygnalizuje system szesnastkowy
438
Typ logiczny (boolowski, boolean)¶
- przyjmuje wartości: prawda lub fałsz
- w Pythonie następujące wartości są utożsamiane z fałszem:
- False
- None
- zero dowolnego typu (0, 0.0, 0j)
- pusta sekwencja '', (), [] lub mapowanie {}
- pozostałe wartości uznawane są za prawdę
Operacje logiczne¶
Operacja | Wynik |
---|---|
x or y | jeśli x jest fałszem, to y, inaczej x |
x and y | jeśli x jest fałszem, to x, inaczej y |
not x | jeśli x jest fałszem, to True, inaczej False |
Operacje logiczne - or¶
print("0 or 0 -> " + str(0 or 0)) print("1 or 0 -> " + str(1 or 0)) print("0 or 1 -> " + str(0 or 1)) print("1 or 1 -> " + str(1 or 1))
0 or 0 -> 0 1 or 0 -> 1 0 or 1 -> 1 1 or 1 -> 1
Operacje logiczne - and¶
print("0 and 0 -> " + str(0 and 0)) print("1 and 0 -> " + str(1 and 0)) print("0 and 1 -> " + str(0 and 1)) print("1 and 1 -> " + str(1 and 1))
Operacje logiczne - not¶
not True
False
not False
True
Dygresja - słowa kluczowe / zastrzeżone¶
x = 1 # zmiennej x przypisz wartość 1 y = 2 # zmiennej y przypisz wartość 2 False = 3 # zmiennej False przypusz wartość 3
File "<ipython-input-88-6d6e4a6b0a3f>", line 3 False = 3 # zmiennej False przypusz wartość 3 ^ SyntaxError: can't assign to keyword
import keyword print(keyword.kwlist) # lista słów kluczowych w Pythonie
['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
Dygresja - niedozwolone nazwy zmiennych¶
- słowa kluczowe
- zaczynające się od cyfry
- zawierające polskie znaki
- zawierające cokolwiek innego niż litery, cyfry i
_
Porównania¶
Operacja | Znaczenie |
---|---|
== | równe |
!= | różne |
< | mniejsze |
> | większe |
<= | mniejsze lub równe |
>= | większe lub równe |
is | ten sam identyfikator |
is not | inny identyfikator |
Porównania¶
1 > 0 # większy niż
True
"Prowadzący" > "Student" # znak po znaku
False
"prowadzący" > "Student" # wielkość ma znaczenie
True
"prowadzący" > "2 studentów" # litera > cyfra
True
Identyfikator zmiennej¶
help(id)
Help on built-in function id in module builtins: id(obj, /) Return the identity of an object. This is guaranteed to be unique among simultaneously existing objects. (CPython uses the object's memory address.)
x = 2 # zmiennej x przypisz wartość 2 id(x) # wyświetl jej id
140685772794432
id dla int¶
x = 2 # zmiennej x przypisz wartość 2 id(x) # wyświetl jej id
140685772794432
y = 2 id(y) # to samo id co x
140685772794432
x is y # zmienne x i y wskazują w to samo miejsce
True
id dla list¶
x = [1, 2, 3] # lista y = [1, 2, 3] # taka sama lista x == y # rzeczywiście taka sama
True
x is y # ale nie ta sama
False
print(id(x), id(y)) # listy mają różne id
140685552423752 140684962057672
x[0] is y[0] # ale elementy już nie
True
x = y # przypisz zmiennej x obieky y x is y # teraz x i y wskazują to samo
True
Mutable vs Immutable¶
- immutable: int, float, complex, str, tuple, (frozen set, bytes)
- przypisanie zmiennej nowej wartości tworzy nowy obiekt w pamięci
- mutable: list, (set, dict, byte array)
- możliwa modyfikacja obiektu
Mutable vs Immutable¶
x = 2 id(x)
140685772794432
x = 3 id(x)
140685772794464
x = [2] id(x)
140685552461384
x.append(3) id(x)
140685552461384
Konsekwencje¶
x = 2 # uwtórz obiekt typu int y = x # y wskazuje na to samo co x y = 5 # zmieniam y - nowe miejsce w pamięci print(x) # x dalej wskazuje na 2
2
x = [1, 2, 3] # utwórz obiekt typu list y = x # y wskazuje na to samo co x print(id(x), id(y))
140684962055816 140684962055816
y[0] = 4 # modyfikuję y print(x) # a zmienia się x...
[4, 2, 3]
Funkcja copy¶
x = [1, 2, 3] # utwórz obiekt typu list y = x.copy() # stwórz kopię tego obiektu print(id(x), id(y)) # teraz są to dwa różne obiekty
140685552556616 140685552460232