+ All Categories
Home > Documents > Typové anotace, testování, efektivita algoritmů - …UNITTESTING •...

Typové anotace, testování, efektivita algoritmů - …UNITTESTING •...

Date post: 03-Mar-2020
Category:
Upload: others
View: 2 times
Download: 0 times
Share this document with a friend
38
TYPOVÉ ANOTACE, TESTOVÁNÍ, EFEKTIVITA ALGORITMŮ IB111 ZÁKLADY PROGRAMOVÁNÍ Nikola Beneš 17. října 2019
Transcript
  • TYPOVÉ ANOTACE, TESTOVÁNÍ, EFEKTIVITA ALGORITMŮIB111 ZÁKLADY PROGRAMOVÁNÍ

    Nikola Beneš17. října 2019

  • is VS. ==

    Porovnání hodnot ==

    a = [1, 2, 3]b = [1, 2, 3]c = aprint(a == b, b == c, a == c) # True, True, True

    Porovnání odkazů is

    print(a is b, b is c, a is c) # False, False, True

    Doporučení

    • nepoužívejte is pro porovnávání hodnot(zdánlivě funguje pro čísla, ale jen pro některá)

    • PEP8 vyžaduje is pro porovnání s None(to je zatím jediný případ, kdy byste is měli použít)

    1

    a = [1, 2, 3]b = [1, 2, 3]c = a

    print(a == b, b == c, a == c) # True, True, True

    print(a is b, b is c, a is c) # False, False, True

  • CHYBY V PROGRAMECH

    Programy obsahují chyby

    • chyby jsou běžné• všichni chybují

    Jak odhalit chyby? / Jak ověřit, že program chyby nemá?

    • jeden z důležitých problémů informatiky• testování (různé úrovně)• (poloautomatická) verifikace

    • stále aktuální výzkumné téma• code review člověkem• důkaz korektnosti• …

    2

  • TESTOVÁNÍ

    (rozsáhlé téma, jen lehce nakousneme)

    • velmi důležitá část vývoje software (až 80 % nákladů)• různé úrovně

    • unit testing (testování malých kusů kódu)• integration testing• system testing• …

    • automatické testování• kód, jehož cílem je otestovat jiný kód

    • co nejvíce různých (druhů) vstupů• snaha otestovat co nejvíce možností

    • testování nikdy není úplné• vstupů je nekonečně mnoho

    3

  • UNIT TESTING

    • testování jednotlivých částí kódu (funkcí)• funkce, které testují, zda kód funguje správně

    def test_fact1():if fact(17) == 355687428096000:

    print("OK")else:

    print("Chyba! Funkce fact dává špatný ""výsledek pro vstup 17.")

    # ...

    • výhody oproti „ručnímu“ testování?• můžeme spouštět opakovaně• např. po každé změně v kódu

    4

    def test_fact1(): if fact(17) == 355687428096000: print("OK") else: print("Chyba! Funkce fact dává špatný " "výsledek pro vstup 17.") # ...

    def test_fact2(): assert fact(17) == 355687428096000, \ "Špatný výsledek pro vstup 17." # ...

    def fact(num): result = 0 for i in range(num): result *= i return result

  • PŘÍKAZ assert

    • způsob, jak do kódu psát podmínky, které zaručeně musí platit• interpret nám je zkontroluje1

    • když neplatí, ukončí program s chybovou hláškou• použití:

    • testování• ověření podmínky, která nutně musí platit• alternativně: vyloučení situací, které nemohou nastat

    def test_fact2():assert fact(17) == 355687428096000, \

    "Špatný výsledek pro vstup 17."# ...

    • nepoužívejte pro kontrolu uživatelského vstupu

    1nejsou-li zapnuty optimalizace, což standardně nejsou5

    def test_fact1(): if fact(17) == 355687428096000: print("OK") else: print("Chyba! Funkce fact dává špatný " "výsledek pro vstup 17.") # ...

    def test_fact2(): assert fact(17) == 355687428096000, \ "Špatný výsledek pro vstup 17." # ...

    def fact(num): result = 0 for i in range(num): result *= i return result

  • PŘÍKLAD POUŽITÍ PŘÍKAZU assert

    def square_root(x, precision=0.01):lower = 0upper = xmiddle = (lower + upper) / 2while abs(middle ** 2 - x) > precision:

    assert lower ** 2 precision: assert lower ** 2

  • PŘÍKLAD POUŽITÍ PŘÍKAZU assert

    def survey(size, preferences):total = sum(preferences) # only needed for assertparties = len(preferences)count = [0] * parties

    for i in range(size):r = random.randint(1, 100)threshold = 0for p in range(parties):

    threshold += preferences[0]assert threshold

  • TYPOVÉ ANOTACE V PYTHONU

  • TYPOVÉ SYSTÉMY (JEN POVRCHNĚ)

    silný vs. slabý typový systém

    • jak velká omezení typový systém klade• jak snadno se ta omezení dají obejít?• není zcela jasně definováno, neostrá hranice

    dynamické vs. statické typování

    • statické: proměnné (funkce apod.) mají svůj typ• typy kontrolovány před spuštěním programu• typicky v době kompilace• typová chyba zabrání spuštění programu

    • dynamické: hodnoty mají svůj typ• typy kontrolovány za běhu programu• typová chyba ukončí program• (nebo vyvolá výjimku, apod.)

    8

  • VÝHODY STATICKÝCH A DYNAMICKÝCH TYPOVÝCH SYSTÉMŮ

    dynamické

    • jednodušší, rychlejší vývoj• stručnější kód• větší flexibilita• snadnější polymorfismus (duck-typing)

    statické

    • bezpečnější• odhalí chyby dřív, než jsou kritické

    • „lépe se vám v noci spí“• často umožňuje rychlejší běh programu• informace o typech může mít dokumentační funkci

    • (a kontroluje ji stroj, ne člověk)

    9

  • TYPOVÉ ANOTACE V PYTHONU

    • od verze 3.6 (omezeně i v některých starších verzích)• přináší (některé) výhody statického typového systémudo dynamicky typovaného jazyka

    • odhalení potenciálních chyb před spuštěním programu• nutnost přemýšlet o typech vede (často) k lepšímu kódu• lepší spolupráce na větších projektech• některá IDE fungují lépe („našeptávání“)

    • interpret Pythonu je ignoruje• používají je nástroje pro statickou analýzu kódu

    • součástí některých IDE• samostatné• v současnosti nejlepší: mypy• http://mypy-lang.org

    10

    http://mypy-lang.org

  • FUNKCE, PROMĚNNÉ

    Typová anotace funkcí

    def is_triangle(a: float, b: float, c: float) -> bool:

    • typy parametrů (tj. co funkce očekává)• typ návratové hodnoty (tj. co funkce slibuje, že vrátí)• pokud funkce nic nevrací, používáme None• neanotované funkce mypy ignoruje (dá se změnit --strict)

    Typová anotace proměnných

    • většinou není potřeba (mypy si umí typ odvodit z přiřazení)• dvě možnosti:

    city: str = "Sparta"soldier_count = 300 # type: int

    • první možnost funguje i bez přiřazení 11

    def is_triangle(a: float, b: float, c: float) -> bool: return a + b > c and a + c > b and b + c > a

    def fact(num): result = 1 for i in range(2, num + 1): result *= i return result

    # try changing the return type annotationdef annotated_fact(num: int) -> int: # mypy automatically deduces the type of result result = 1 for i in range(2, num + 1): result *= i return result

    # these are not really neededcity: str = "Sparta"soldier_count = 300 # type: int

    # this is needed, why?temperature: float = 37

    def say_hello(language: str, name: str) -> None: # this is again not really needed hello: str if language == "en": hello = "Hello" elif language == "dk": hello = "Hei" else: hello = "Saluton"

    print(hello + ", " + name + "!")

  • SLOŽITĚJŠÍ TYPY: LIST, TUPLE

    • se složitějšími typy se zachází speciálně• potřebujeme knihovnu typing

    from typing import List, Tuple

    • anotace pro seznamy: List[typ]• anotace pro ntice: Tuple[typ1, typ2, typ3, ...]

    def average(numbers: List[float]) -> float:return sum(numbers) / len(numbers)

    my_list: List[int] = []

    def minmax(num1: int, num2: int) -> Tuple[int, int]:return min(num1, num2), max(num1, num2)

    12

    from typing import List, Tuple

    def average(numbers: List[float]) -> float: return sum(numbers) / len(numbers)

    # we need the annotation here, mypy cannot guess the typemy_list: List[int] = []

    def minmax(num1: int, num2: int) -> Tuple[int, int]: return min(num1, num2), max(num1, num2)

  • OPTIONAL, TYPOVÁ SYNONYMA

    • funkce, které někdy vrací hodnotu a někdy None

    from typing import Optional

    def safe_divide(p: float, q: float) -> Optional[float]:return None if q == 0 else p / q

    • typová synonyma (pro čitelnější anotace)

    Book = Tuple[str, str, float]

    def get_book(database: List[Book], title: str) \-> Optional[Book]:

    for book in database:if book[0] == title:

    return bookreturn None 13

    from typing import List, Tuple, Optional

    # title, author, priceBook = Tuple[str, str, float]

    def get_book(database: List[Book], title: str) \ -> Optional[Book]: for book in database: if book[0] == title: return book return None

    my_books = [ ("Dune", "Frank Herbert", 686.90), ("The Absolute Sandman", "Neil Gaiman", 1276.70), ("Doupě latinářů", "Ivan Wernish", 131),]

    from typing import Optional

    def safe_divide(p: float, q: float) -> Optional[float]: return None if q == 0 else p / q

    # this is a mypy-error:# print(safe_divide(3, 7) + 1)

    # this is OK:result = safe_divide(3, 7)if result is not None: print(result + 1)

  • JAK POUŽÍVAT TYPOVÉ ANOTACE?

    Chcete-li používat typové anotace (nebo vyžaduje-li to úloha) …

    • anotujte funkce (i pomocné)• parametry i návratovou hodnotu

    • zkuste spustit mypy, nejlépe s volbou --strict• pokud je všechno v pořádku, jste hotovi• pokud si mypy stěžuje, přečtěte si, co říká …• … a podle toho opravte svůj kód• nejste-li si jistí, co hláška znamená

    • zkuste si ji přečíst (a přeložit z angličtiny)• zeptejte se (cvičící(ho), poradce, na diskusním fóru, …)

    • proměnné většinou není třeba anotovat• kdyby to bylo nutné, mypy si bude stěžovat

    14

  • EFEKTIVITA ALGORITMŮ

  • DĚLITELÉ ČÍSLA

    def divisors1(num: int) -> List[int]:result = []for divisor in range(1, num + 1):

    if num % divisor == 0:result.append(divisor)

    return result

    • jak tento kód vylepšit?

    • počítat jen do poloviny num• využít toho, že divisor i num // divisor jsou děliteli• co když chceme, aby byli seřazení?

    15

    import mathfrom typing import List

    def divisors1(num: int) -> List[int]: result = [] for divisor in range(1, num + 1): if num % divisor == 0: result.append(divisor) return result

    def divisors2(num: int) -> List[int]: result = [] for divisor in range(1, num // 2 + 1): if num % divisor == 0: result.append(divisor) result.append(num) return result

    def divisors3(num: int) -> List[int]: max_divisor = round(math.sqrt(num)) result = [1, num] for divisor in range(2, max_divisor + 1): if num % divisor == 0: result.append(divisor) result.append(num // divisor) # try running this code without the following if statement; what happens? if result[-1] == result[-2]: result.pop() # try running this code without the following line; what happens? result.sort() return result

    def divisors4(num: int) -> List[int]: max_divisor = round(math.sqrt(num)) small, large = [1], [num] for divisor in range(2, max_divisor + 1): if num % divisor == 0: small.append(divisor) large.append(num // divisor) if small[-1] == large[-1]: large.pop() large.reverse() return small + large

  • DĚLITELÉ ČÍSLA

    def divisors2(num: int) -> List[int]:result = []for divisor in range(1, num // 2 + 1):

    if num % divisor == 0:result.append(divisor)

    result.append(num)return result

    • jak tento kód vylepšit?• počítat jen do poloviny num

    • využít toho, že divisor i num // divisor jsou děliteli• co když chceme, aby byli seřazení?

    15

    import mathfrom typing import List

    def divisors1(num: int) -> List[int]: result = [] for divisor in range(1, num + 1): if num % divisor == 0: result.append(divisor) return result

    def divisors2(num: int) -> List[int]: result = [] for divisor in range(1, num // 2 + 1): if num % divisor == 0: result.append(divisor) result.append(num) return result

    def divisors3(num: int) -> List[int]: max_divisor = round(math.sqrt(num)) result = [1, num] for divisor in range(2, max_divisor + 1): if num % divisor == 0: result.append(divisor) result.append(num // divisor) # try running this code without the following if statement; what happens? if result[-1] == result[-2]: result.pop() # try running this code without the following line; what happens? result.sort() return result

    def divisors4(num: int) -> List[int]: max_divisor = round(math.sqrt(num)) small, large = [1], [num] for divisor in range(2, max_divisor + 1): if num % divisor == 0: small.append(divisor) large.append(num // divisor) if small[-1] == large[-1]: large.pop() large.reverse() return small + large

  • DĚLITELÉ ČÍSLA

    def divisors3(num: int) -> List[int]:max_divisor = round(math.sqrt(num))result = [1, num]for divisor in range(2, max_divisor + 1):

    if num % divisor == 0:result.append(divisor)result.append(num // divisor)

    if result[-1] == result[-2]:result.pop()

    result.sort()return result

    • jak tento kód vylepšit?• počítat jen do poloviny num• využít toho, že divisor i num // divisor jsou děliteli• co když chceme, aby byli seřazení? jde to jinak?

    15

    import mathfrom typing import List

    def divisors1(num: int) -> List[int]: result = [] for divisor in range(1, num + 1): if num % divisor == 0: result.append(divisor) return result

    def divisors2(num: int) -> List[int]: result = [] for divisor in range(1, num // 2 + 1): if num % divisor == 0: result.append(divisor) result.append(num) return result

    def divisors3(num: int) -> List[int]: max_divisor = round(math.sqrt(num)) result = [1, num] for divisor in range(2, max_divisor + 1): if num % divisor == 0: result.append(divisor) result.append(num // divisor) # try running this code without the following if statement; what happens? if result[-1] == result[-2]: result.pop() # try running this code without the following line; what happens? result.sort() return result

    def divisors4(num: int) -> List[int]: max_divisor = round(math.sqrt(num)) small, large = [1], [num] for divisor in range(2, max_divisor + 1): if num % divisor == 0: small.append(divisor) large.append(num // divisor) if small[-1] == large[-1]: large.pop() large.reverse() return small + large

  • DĚLITELÉ ČÍSLA

    def divisors4(num: int) -> List[int]:max_divisor = round(math.sqrt(num))small, large = [1], [num]for divisor in range(2, max_divisor + 1):

    if num % divisor == 0:small.append(divisor)large.append(num // divisor)

    if small[-1] == large[-1]:large.pop()

    large.reverse()return small + large

    • jak tento kód vylepšit?• počítat jen do poloviny num• využít toho, že divisor i num // divisor jsou děliteli• co když chceme, aby byli seřazení? je tohle lepší?

    15

    import mathfrom typing import List

    def divisors1(num: int) -> List[int]: result = [] for divisor in range(1, num + 1): if num % divisor == 0: result.append(divisor) return result

    def divisors2(num: int) -> List[int]: result = [] for divisor in range(1, num // 2 + 1): if num % divisor == 0: result.append(divisor) result.append(num) return result

    def divisors3(num: int) -> List[int]: max_divisor = round(math.sqrt(num)) result = [1, num] for divisor in range(2, max_divisor + 1): if num % divisor == 0: result.append(divisor) result.append(num // divisor) # try running this code without the following if statement; what happens? if result[-1] == result[-2]: result.pop() # try running this code without the following line; what happens? result.sort() return result

    def divisors4(num: int) -> List[int]: max_divisor = round(math.sqrt(num)) small, large = [1], [num] for divisor in range(2, max_divisor + 1): if num % divisor == 0: small.append(divisor) large.append(num // divisor) if small[-1] == large[-1]: large.pop() large.reverse() return small + large

  • PŘÍKLAD: OTRÁVENÁ STUDNA

    • máme osm studen, víme, že (právě) jedna z nich je otrávená• laboratorní rozbor

    • pozná přítomnost jedu ve vodě• je drahý

    • je navíc časově náročný

    • kolik rozborů potřebujeme k tomu, abychom s jistotou našliotrávenou studnu?

    • všechny rozbory chceme dělat zároveň

    Řešení: stačí tři rozbory• každý rozbor nám zmenší „okruh podezřelých“ na polovinu

    • můžeme smíchat vodu z více studní

    16

  • PŘÍKLAD: OTRÁVENÁ STUDNA

    • máme osm studen, víme, že (právě) jedna z nich je otrávená• laboratorní rozbor

    • pozná přítomnost jedu ve vodě• je drahý• je navíc časově náročný

    • kolik rozborů potřebujeme k tomu, abychom s jistotou našliotrávenou studnu?

    • všechny rozbory chceme dělat zároveň

    Řešení: stále stačí tři rozbory• jeden rozbor: voda ze studní č. 1, 2, 3, 4• druhý rozbor: voda ze studní č. 1, 2, 5, 6• třetí rozbor: voda ze studní č. 1, 3, 5, 7• jak poznáme, která studna je otrávená?

    16

  • PŘÍKLAD: HÁDÁNÍ ČÍSLA

    • myslím si přirozené číslo mezi 1 a 1000 (včetně)• povoleny pouze otázky typu „Je myšlené číslo menší než N?“• kolik otázek potřebujete na odhalení čísla?

    • těžší: kolik předem formulovaných otázek potřebujete?

    • kdybyste měli pouze k dispozici pouze K otázek,v jakém rozsahu jste schopni čísla hádat?

    17

  • PŘÍKLAD: HÁDÁNÍ ČÍSLA

    Řešení

    • půlení intervalu• 𝑁 čísel: potřebujeme cca log2 𝑁 otázek• 𝐾 otázek: umíme vyřešit rozsah velikosti 2𝐾

    Řešení těžší varianty (předem formulované otázky)

    • dotazy na jednotlivé číslice v binárním zápisu čísla• totéž jsme dělali u druhé varianty otrávené studny• opět stačí cca log2 𝑁 otázek

    18

  • PŘIPOMENUTÍ: LOGARITMUS

    𝑥 = 𝑏𝑦 právě tehdy, když 𝑦 = log𝑏(𝑥)

    log10(1000) = 3 log3(81) = 4log2(16) = 4 log2(2) = 1log2(1024) = 10 log5(1) = 0log2(

    √2) = 0.5 log0.5(4) = − 2

    • log𝑏(𝑥 ⋅ 𝑦) = log𝑏(𝑥) + log𝑏(𝑦)• 𝑏𝑙𝑜𝑔𝑏(𝑥) = 𝑥

    19

  • VYHLEDÁVÁNÍ

    • častý problém:• web, slovník, informační systémy, databáze• dílčí krok v mnoha algoritmech

    zdroj obrázku: http://www.bugemos.com/

    20

    http://www.bugemos.com/

  • VYHLEDÁVÁNÍ

    Vyhledávání v obecném seznamu

    • vstup: seznam čísel2 + dotaz (číslo)• výstup: odpověď True/False, jestli je číslo v seznamu• alt. výstup: index čísla v seznamu (nějaká speciální hodnota,např. None, pokud číslo v seznamu není)

    • v nejhorším případě musíme projít celý seznam• časová složitost: cca délka seznamu• jde to lépe? v obecném seznamu ne

    2nebo řetězců, nebo čehokoli jiného, co se dá hledat

    21

  • LINEÁRNÍ VYHLEDÁVÁNÍ

    def contains(haystack: List[int], needle: int) -> bool:for element in haystack:

    if element == needle:return True

    return False

    def index_of(haystack: List[int], needle: int) \-> Optional[int]:

    for index, element in enumerate(haystack):if element == needle:

    return indexreturn None

    • vyhledávání v Pythonu• operátor in (vrací bool)• seznam.index(prvek) – při nenalezení zahlásí ValueError 22

    from typing import List, Optional

    def contains(haystack: List[int], needle: int) -> bool: for element in haystack: if element == needle: return True return False

    def index_of(haystack: List[int], needle: int) \ -> Optional[int]: for index, element in enumerate(haystack): if element == needle: return index return None

  • VYHLEDÁVÁNÍ

    Vyhledávání v seřazeném seznamu

    • vstup: seřazený seznam čísel + dotaz (číslo)• výstup: odpověď True/False, jestli je číslo v seznamu,případně index nalezeného prvku

    Řešení

    • „naivní“ řešení: procházení celého seznamu• složitost cca délka seznamu (lineární)• použitelné pro krátké seznamy• nepoužitelné pro delší seznamy

    • „rozumné“ řešení: půlení intervalu• složitost logaritmická k délce seznamu• jak implementovat?

    23

  • VYHLEDÁVÁNÍ

    Binární vyhledávání

    • půlení intervalu (podobné hádání čísel, výpočtu odmocniny, …)• podíváme se na prostřední prvek seznamu

    • podle jeho hodnoty buď skončíme,nebo pokračujeme doleva nebo doprava

    • udržujeme si „dolní“ a „horní“ mez

    24

  • BINÁRNÍ VYHLEDÁVÁNÍ

    def binary_search(haystack: List[int], needle: int) \-> bool:

    lower_bound = 0upper_bound = len(haystack) - 1while lower_bound bool: lower_bound = 0 upper_bound = len(haystack) - 1 while lower_bound

  • BINÁRNÍ VYHLEDÁVÁNÍ

    Zajímavé varianty k rozmyšlení

    • co když se v seznamu prvky mohou opakovat?• index prvního prvku s danou hodnotou• index posledního prvku s danou hodnotou• jak si zachovat efektivitu?

    • co když prvek v seznamu není, ale zajímalo by nás, kam by sezařadil?

    • poslední prvek menší než hledaný• první prvek větší než hledaný

    26

  • SLOŽITOST ALGORITMŮ (LETMO)

    Časová složitost

    • funkce, která délce vstupu přiřazuje počet kroků• typicky měříme nejhorší případ

    • (existují i jiné možnosti)• je třeba si ujasnit:

    • co jsou základní kroky, které počítáme• co je velikost vstupu

    • při počítání se seznamy (většinou):• základní kroky jsou operace s jednotlivými prvky• velikost vstupu je délka seznamu

    27

  • SLOŽITOST ALGORITMŮ (LETMO)

    Asymptotická časová složitost

    • zajímá nás pouze rychlost růstu funkcí• třída 𝒪(𝑓(𝑛)) – funkce, které rostou stejně rychle jako 𝑓(𝑛)nebo pomaleji

    • zanedbáváme nedůležité části složitostní funkce• násobení konstantou• přičítání konstanty• nevedoucí členy polynomů, apod.

    • příklady:• třída 𝒪(𝑛) zahrnuje všechny lineární funkce(𝑛, 3𝑛 + 7, 1000𝑛 + 9, …)

    • třída 𝒪(𝑛2) zahrnuje všechny kvadratické funkce(𝑛2, 6𝑛2 + 11, 20𝑛2 − 17𝑛 + 9, 𝑛2 + 𝑛 + 3, …)

    • třída 𝒪(log 𝑛) zahrnuje všechny logaritmické funkce(o základu > 1)

    28

  • SLOŽITOST VYHLEDÁVÁNÍ (BINÁRNÍ VS. LINEÁRNÍ)

    Jak moc je logaritmická složitost lepší než lineární?

    • řekněme (jen pro účely tohoto slajdu), že• lineární vyhledávání má složitost 5 ⋅ 𝑛 operací• binární vyhledávání má složitost 20 ⋅ log2(𝑛) operací• jedna operace trvá 1 ns

    𝑛 binární vyhledávání lineární vyhledávání8 60 ns 40 ns16 80 ns 80 ns256 160 ns 1280 ns65536 320 ns 327,68 µs

    4294967296 640 ns 21,48 s18446744073709551616 1,28 µs 2922,78 let

    29

  • VYHLEDÁVÁNÍ A DATOVÉ STRUKTURY

    • seřazený seznam• umíme rychle vyhledávat, ale přidávání prvků je pomalé• proč?musíme udržovat seřazenostvkládání dovnitř seznamu je lineární(prvky za místem, kam přidáváme, musíme odsunout o kus dál)

    • datové struktury pro rychlé vyhledávání, vkládání i mazání prvků(pro zajímavost)

    • vyhledávací stromy• hašovací tabulky• v Pythonu: uvidíme později

    30

  • PŘÍŠTĚ: ŘADICÍ ALGORITMY

    • oblíbené algoritmické téma• anglicky „sorting algorithms“, česky někdy „třídicí algoritmy“• cílem je seřadit data v seznamu• existuje mnoho různých algoritmů• většina programovacích jazyků má ve své standardní knihovněfunkci sort() nebo podobnou

    • proč se tím tedy zabýváme?• ukázka programů se seznamy• algoritmy s různou myšlenkou• „programátorská tradice“

    • k zamyšlení do příště:• jak byste seřadili seznam? (v Pythonu)• jak řadíte „ručně“? (karty, knihy, koření, …)

    31

    Typové anotace v PythonuEfektivita algoritmů


Recommended