Proměnné, paměť, typy IBil 1 Základy programování Radek Pelánek 2018 Rozcvička I a = [3, 1, 7] print(sorted(a)) print(a) b = [4, 3, 1] print(b.sort()) print(b) 2/63 Rozcvička a = ["magic"] a.append(a) print (a [1] [1] [1] [1] [1] [0] [1] [0] [0] [0]) „důležité technické detaily" • globální a lokální proměnné • reprezentace dat v paměti, kopírování • předávání parametrů funkcím • typy základní témata obecně důležitá detaily specifické pro Python Dnešní programy Varování: Dnešní programy jsou vesměs „úchylné". • minimalistické ukázky důležitých jevů • nikoliv pěkný, prakticky používaný kód Python Tutor - vizualizace Vizualizace použité ve slidech: http://www.pythontutor.com Odkazy na dnešní ukázky: https://www.fi.muni.cz/~xpelanek/IBlll/tutor-codes.html Doporučeno projít si interaktivně. 6/63 Názvy proměnných - konvence • konstanty - velkými písmeny a běžné proměnné: • smysluplná slova • víceslovné názvy: lower_case_with_undersc • krátké (jednopísmenné) názvy: • indexy • souřadnice: x, y • pomocné proměnné s velmi lokálním využitím 4 □ ► < [S ► < Globální a lokální proměnné Globální proměnné • definovány globálně (tj. ne uvnitř fun • jsou viditelné kdekoli v programu Lokální proměnné • definovány uvnitř funkce • jsou viditelné jen ve své funkci Rozsah proměnných obecněji • proměnné jsou viditelné v rámci svého „rozsahu" • rozsahem mohou být: • funkce • moduly (soubory se zdrojovým kódem) • třídy (o těch se dozvíme později) • a jiné (závisí na konkrétním jazyce) relevantní terminologie: „namespace", „scope" 9/63 Globální a lokální proměnné a = "This is global." def examplel(): b = "This is local." print(a) print(b) examplel() # This is global. # This is local. print(a) # This is global. print(b) # ERROR! # NameError: name ,b> is not defined Globální a lokální proměnné Python 3.6 a = "This is global." def examplel(): b = "This is local." print ta) print(b) # This is global # This is local. # This is global # ERROR! 1 2 3 4 5 6 7 examplel() 9 print(a) 11 printib) Edit code I Live programming Print output (drag lower right corner to resize) This i 5 global. Fra rnes Global frame examplel This is global examplel b "Thi ü 1ü local Objects function examplel() 1 vytváříme novou lokální proměnnou, neměníme tu globální a = "Think global." def example2(): a = "Act local." print(a) print(a) # Think global. example2() # Act local. print(a) # Think global. 12/63 Globální a lokální proměnné Python 3.6 a = "Think global." 2 def example?(): a = "Act local." —► 5 print(a) 6 print(a) # Think global, example2O # Act local. 3 print(a) # Think global. Edit code | Live programming st executed ^cute ) set a breakpoint; use the Back and Forward buttons to jump there. Print output (drag lower right corner to resize) Think global Frames Global frame example2 Think global Objects fL"CtÍO" example2() example2 a "Act local." Globální a lokální proměnné Jak měnit globální proměnné? a = "Think global." def example3(): global a a = "Act local." print(a) print(a) # Think global example3() # Act local. print(a) # Act local. Lokální proměnné: deklarace lokální proměnná vzniká, pokud je přirazení kdekoli uvnitř f u n kce a = "Think global, def example4(change_opinion=False): print(a) if change_opinion: a = "Act local." print("Changed opinion:", a) print(a) # Think global. example4() # ERROR! # UnboundLocalError: local variable 3a3 reference # assignment < □ ► <^ ► < i ► < z= ► t Globální a lokální proměnné: příklad a = 5 def testi (): print(a) def test2(): print(a) a = 8 testi() # 5 test2() # UnboundLocalError □ Rozsah proměnných: for cyklus • rozsah proměnné v Pythonu není pro „dílčí blok kódu ale pro celou funkci (resp. globální kód) • častá chyba (záludný preklep): proměnná for cyklu použita po ukončení cyklu n = 9 for i in range(n): print(i) if i °/0 2 == 0: print("I like even length lists") Globální a lokální proměnné a proměnné interně uloženy ve slovníku • výpis: globalsO, locals() def functionO : x = 100 s = "dog" print(locals()) a = [1, 2, 3] x = 200 functionO print(globals()) void test(int a, intfe b) { a = a + 1; b = b + 1; } int main() { int a = 1; int b = 1; std::cout « test(a, b); std::cout « } n ~ . ii n ~ . n « a « ", b: " « b « "\n"; « a « ", b: " « b « "\nM; 30/63 Predávaní parametru v Pythonu Předávání parametrů v Pythonu • paramater drží odkaz na predanou proměnnou • změna parametru změní i predanou proměnnou • pro neměnitelné typy tedy v podstatě funguje jako predávaní hodnotou • čísla, řetězce, ntice (tuples) • pro měnitelné typy jako předávání odkazem o pozor: přiřazení znamená změnu odkazu Připomenutí: • neměnitelné typy: int, str, tuple, ... • měnitelné typy: list, diet, ... Predávaní parametru: ukázky číselný parametr je neměnitelný, toto nic neprovede def update_param_int(x): x = x + 1 a = 1 print(a) # 1 update_param_int(a) print(a) # 1 4 □ ► < [S ► < seznam je měnitelný, změna se projeví i mimo funkci def update_param_list(x): x.append(3) a = [1, 2] print (a) # [1, 2] update_param_list(a) print (a) # [1, 2, 3] 33/63 Predávaní parametru: ukázky odkaz se zmení na nový seznam, původní je nezměněn -změna se neprojeví mimo funkci def change_param_list(x): x = [1, 2, 3] a = [1, 2] print (a) # [1, 2] change_param_list(a) print (a) # [1, 2] 4 □ ► 4 ^ >■ 4 > 4 S ► 34/63 Predávaní parametru: kvíz def test(s): s.append(3) s = [42, 17] s.append(9) print(s) t = [1, 2] test(t) print(t) Předávání parametrů: vizualizace Python 3.6 Print output (drag lower right corner to resize) 1 def test(s): 2 s.append(3) 3 s = [42, 17] 4 s.append(S) 5 print (s) 6 7 t = [1, 2] 3 testet) 9 print(t) Edit code I Live programming ted sakpoint; use the Back and Forward buttons to jump there. Frames Objects function test(s) Ní; Ní: 0 l 2 42 17 9 36/63 Práce s parametry: príklad def change_list(alist, value): alist.append(value) def return_new_list(alist, value) newlist = alist [:] newlist append(value) return newlist Predávaní parametru: príklad += Operátor += různé chování pro neměnné typy a pro seznamy def increment(x): print(x, id(x)) x += 1 print(x, id(x)) p = 42 increment(p) print(p, id(p)) def add_to_list (s) : print(s, id(s)) s += [1] print(s, id(s)) t = [1, 2, 3] add_to_list(t) print(t, id(t)) 38/63 Predávaní parametru: += a Pozor na rozdíl mezi = a += u seznamů def add_to_listl(s): print(s5 id(s)) s += [1] print(s, id(s)) t = [1, 2, 3] add_to_listl(t) print(t) def add_to_list2(s): print(s, id(s)) s = s + [1] print(s, id(s)) t = [1, 2, 3] add_to_list2(t) print(t) # [1, 2, 3, 1] # ??? 39/63 Předávání parametrů: vizualizace Python 3.6 def add_to_List2(s) prínt(5, id(sj) s = s + [1] prinifs, íc(sj) 1 2 3 4 5 t = [1, 2, 3] add_to_list2(t) 8 print(t)_ Edit code | Live programming :uted ireakpoint; use the Back and Forward buttons to jump there. =0 — Print output (drag lower right corner to resize) [1, 2, 3] 1403Q5100337672 Frames Global frame < Rank I I I I ast r» Objects function add_to_li st2(s) list 0 1 2 1 2 3 list 0 l 2 1 2 3 1 40/63 41/63 Kahoot: Program A a = 1 b = [1, 2, 3] def test(): a = 5 b[0] =5 test O print (a, b[0]) 42/63 def test(b): b.append(3) b = [4, 5] b.append(6) a = [1, 2] test(a) print(a) 43/63 Predávaní výsledku funkcí funkce mají: • libovolný počet parametrů • právě jeden výstup (return x) Co když chceme z funkce vrátit více hodnot? Elementární příklad: dělení se zbytkem 44/63 Jak předat více výsledků? • n-tice (možno zapisovat i bez závorek) def division_with_remainder(a, b): return a // b, a °/0 b div, mod = division_with_remainder(23, 4) 45/63 Jak předat více výsledků? • slovník („pojmenované" výstupy) def division_with_remainder(a, b): return {"div": a // b, "mod": a °/0 b} result = division_with_remainder(23, 4) print (result ["div11] , result ["mod"]) 46/63 Kopírování objektů Vytvoření aliasu b = a • odkaz na stejnou věc Mělká kopie b = a[:] nebo b = list (a) • vytváříme nový seznam, ale prvky tohoto seznamu jsou aliasy • obecně i pro jiné typy než seznamy (knihovna copy) • b = copy.copy(a) Hluboká kopie • kompletní kopie všech dat • obecné řešení (opět knihovna copy) • b = copy.deepcopy(a) 47/63 Kopírování objektů mělká kopie [3, 5] [2,9] [1,7] listB hluboká kopie [3, 5] [2,9] [1,7] [3, 5] [2, 9] [1,7] import copy a = [[3, 5] , [2, 9] , [1, 7]] b = a c = a[:] d = copy.deepcopy(a) a[0] [0] = 100 print (b [0] [0] , c [0] [0] , d[0][0]) a[0] = [200, 200] print (b [0] [0] , c [0] [0] , d [0] [0]) 49/63 Datové typy Datové typy určují: • význam dat • operace, které lze s daty provádět • hodnoty, kterých mohou data nabývat • bool • int, float, complex - číselné typy • str - řetězec • list - seznam • tuple - n-tice • diet - slovník • set - množina (vyber nejdulezitejsichj 51/63 print(type(3)) print(type(3.0)) print(type(3==0)) print(type("3")) print(type([3])) print(type((3,0))) print(type({3:0})) print(type({3})) Typy: kvíz type(3) type(3.0) type(3==0) type("3") type ([3]) type((3,0)) type({3:0}) type({3}) # }floať> 'booľ> 'str>> >list>> 'tuple '> 'dicť> 'seť> 53/63 • neměnitelné (immutable): bool, int, float, str, tuple • měnitelné (mutable): list, diet, set Příklady, kde důležité: • změna indexováním • předávání parametrů funkcím a indexování slovníku 54/63 • None - jedinečná hodnota typu NoneType • význam: „prázdné", „žádná hodnota" • využití: např. defaultní hodnota parametrů funkcí • implicitní návratová hodnota z funkcí (pokud nepoužijeme return) 55/63 ravdivostnŕ hodnota if value: print("foo") Pro které z těchto hodnot value se vypíše f < True, False, 3, 0, 3.0, -3, [3], [] , None ravdivostnŕ hodnota test je úspěšný ("tme") vždy, kromě následujících případů • konstanty: None, Falše • nulové hodnoty u numerických typů: 0, 0.0, Oj • prázdné sekvence (nulová délka měřená pomocí len) D. (). (mírně zjednodušeno, např. u objektů může být komplikovanější) Dynamická kontrola typů • type(x) - zjištění typu • isinstance(x, t) - test, zdaje proměnná určitého typu values = [3, 8, "deset", 4, "dva", "sedm", 6] s = 0 for value in values: if isinstance(value, int): s += value else: print("Not int:", value) print("Sum of ints:", s) 58/63 • Python používá dynamické typování • výhody: stručný, flexibilní kód • nevýhody: náročnější ladění, uvažování o problémech, čitelnost • typové anotace (type hints): • volitelné, neovlivňují běh programu • možnost statické kontroly (např. mypy) • integrace v některých IDE def greeting(name: str) -> str: return "Hello 11 + name 59/63 Načítaní vstupu od uživatele: input x = input("Give me a large number:") x = int(x) print("My number is larger:", x+1) • input vrací řetězec • typicky nutno přetypovát • Python2: odlišné chování (input, raw_input) 60/63 • Co když uživatel zadá místo čísla "deset"? • častý přístup: doufat, že se to nestane • základní přístup: důsledně před každou operací kontrolovat vstupy • u složitějších programů nepřehledné • sofistikovanější přístup: výjimky < S ► 4 ± k 4 S ► 61/63 try: x = input("Give me a large number:") x = int(x) print("My number is larger:", x+1) except ValueError: print("Sorry, that is not a valid number") Nad rámec tohoto kurzu. 62/63 a představa o reprezentaci v paměti je potřeba • globální, lokální proměnné • předávání parametrů funkcím • mělká vs. hluboká kopie o typy, měnitelné, neměnitelné 63/63