Týden 2: Poznámky

Řetězená porovnání

Python umožňuje řetězit operátory porovnání. Například:

    >>> x = 15
    >>> 10 <= x <= 20
    True

Řetězené porovnání 10 <= x <= 20 má přesně stejný význam jako 10 <= x and x <= 20. Lze řetězit i několik operátorů porovnání:

    >>> 10 < 20 < 25 < 35
    True

To má stejný význam jako 10 < 20 and 20 < 25 and 25 < 35.

Řetězená porovnání jsou zvlášť užitečná, když chceme ověřit, že několik hodnot je stejných:

    >>> x = 5 + 5
    >>> y = 2 + 8
    >>> z = 1 + 9
    >>> x == y == z    # test whether x, y, and z are all equal
    True

Další informace o rozsazích

V minulé přednášce jsme viděli, že range(a, b) představuje posloupnost celých čísel od a až po číslo těsně před b. Například cyklus

    for n in range(1, 10):
        print(n)

vypíše:

    1
    2
    3
    4
    5
    6
    7
    8
    9

range(a)

Funkci range() lze zavolat také s jediným argumentem. range(a) znamená totéž co range(0, a): vytvoří celá čísla od 0 až po číslo těsně před a. Například cyklus

    for n in range(5):
        print(n)

vypíše:

    0
    1
    2
    3
    4

Pro každé nezáporné celé číslo n vytvoří range(n) právě n různých čísel. Cyklus for nad range(0) tedy proběhne nula­krát a jeho tělo se vůbec nevykoná. Následující kód nevypíše nic:

    for n in range(0):
        print(n)

range(a, b, c)

Funkci range() lze zavolat také se třemi argumenty. range(a, b, c) představuje celá čísla od a až po číslo těsně před b, přičemž se postupuje po krocích velikosti c. Například cyklus

    for n in range(4, 20, 2):
        print(n)

vytvoří tento výstup:

    4
    6
    8
    10
    12
    14
    16
    18

Jinými slovy, cyklus generuje čísla od 4 až po číslo těsně před 20 a při každém kroku přičítá 2.

Hodnota kroku může být i záporná. Cyklus

    for n in range(10, 0, -1):
        print(n)

vypíše:

    10
    9
    8
    7
    6
    5
    4
    3
    2
    1

Obecně platí, že pokud je c > 0, cyklus

    for n in range(a, b, c):
        … (body) …

je ekvivalentní následujícímu kódu:

    n = a
    while n < b:
        … (body) …
        n += c

Z tohoto kódu by mělo být zřejmé například to, že range(10, 20, 30) vytvoří jedinou hodnotu (10).

continue

Minulý týden jsme se seznámili s příkazem break, který ukončí cyklus. Příbuzný příkaz continue ukončí aktuální iteraci cyklu a pokračuje další iterací.

Následující cyklus například sečte čísla od 1 do 100, ale pomocí příkazu continue přeskočí číslo 28:

    sum = 0

    for i in range(1, 101):
        if i == 28:
            continue
        sum += i

    print(sum)

V tomto konkrétním cyklu bychom mohli příkaz continue jednoduše nahradit podmínkou s operátorem !=:

    for i in range(1, 101):
        if i != 28:
            sum += i

Příkaz continue se ale někdy hodí, když za ním následuje další kód: můžeme se tak vyhnout přesouvání veškerého tohoto kódu do vnořeného bloku.

Vnořené cykly

Často se jeden cyklus vkládá do druhého. Například:

    for x in 'abcd':        # outer loop
        for y in 'efg':     # inner loop
            print (x + y)

Při každé iteraci vnějšího cyklu proběhne celý vnitřní cyklus. Program vypíše:

    ae
    af
    ag
    be
    bf
    bg
    ce
    cf
    cg
    de
    df
    dg

Všimněte si, že příkazy break a continue ovlivňují pouze nejvnitřnější cyklus, ve kterém se nacházejí. Přidejme například do předchozího programu příkaz break:

    for x in 'abcd':        # outer loop
        for y in 'efg':     # inner loop
            print (x + y)
            if y == 'f':
                break

Tato verze vytvoří následující výstup:

    ae
    af
    be
    bf
    ce
    cf
    de
    df

Příkaz break ukončí vnitřní cyklus (for y), takže se spustí další iterace vnějšího cyklu (for x).

Matematické funkce

Python obsahuje několik matematických funkcí, které jsou vždy dostupné. Funkce abs(x) vypočítá absolutní hodnotu čísla x, často zapisovanou jako |x|:

    >>> abs(-5)
    5

Funkce round() zaokrouhlí číslo typu float na nejbližší celé číslo:

    >>> round(2.3)
    2

Funkce max() vypočítá maximum ze dvou nebo více čísel:

    >>> max(10, 5)
    10
    >>> max(10, 5, 20, 3)
    20

Podobně funkce min() vypočítá minimum ze dvou nebo více čísel:

    >>> min(100, 77, 200, 88)
    77

Chcete-li získat přístup k dalším matematickým funkcím, importujte na začátku programu modul math:

    import math

Stručná referenční příručka ke knihovně Pythonu uvádí v tomto modulu řadu užitečných funkcí, například:

Chcete-li některou z těchto funkcí nebo konstant použít, napište math. a za něj její název. Například:

    >>> import math
    >>> math.sqrt(2)
    1.4142135623730951
    >>> math.cos(math.pi)
    -1.0

Náhodná čísla

Stručná referenční příručka ke knihovně uvádí také různé funkce pro generování náhodných čísel. Chcete-li je používat, nejprve napište import random. K těmto funkcím se budeme často vracet.

Užitečná je funkce random.randint(a, b), která vrací náhodné celé číslo n z rozsahu a ≤ n ≤ b. Napišme program, který hodí zadaným počtem šestistěnných kostek a vypíše součet jejich hodnot:

    import random

    n = int(input('How many dice? '))

    sum = 0
    for i in range(n):
        sum += random.randint(1, 6)

    print('The total is', sum)

Spusťme jej:

    $ py dice.py
    How many dice? 100
    The total is 337

K zamyšlení: pokud hodíme 100 kostkami a vypočítáme jejich součet, bude tento součet obvykle menší, nebo větší než 337?

ASCII a Unicode

Počítače ukládají text pomocí kódované znakové sady, která každému znaku přiřazuje jedinečné číslo nazývané kódový bod. V současnosti se téměř ve všech softwarových systémech používají dvě znakové sady.

První, ASCII, obsahuje pouze 128 znaků; její kódové body jsou v rozsahu 0 až 127. Například znak A má v ASCII číslo 65, znak B číslo 66 a znak a číslo 97. Kódové body se často zapisují v šestnáctkové soustavě; kód znaku A je tedy 65₁₀ = 41₁₆ a kód znaku a je 97₁₀ = 61₁₆.

ASCII zahrnuje všechny znaky běžné anglické klávesnice: velká a malá písmena latinské abecedy A–Z/a–z, číslice 0–9 a různé interpunkční znaky, například $, % a &. Neobsahuje znaky s diakritikou, jako jsou č nebo ř.

Tabulku všech znaků ASCII najdete na asciitable.com.

ASCII obsahuje také různé bílé znaky, které na vytištěné stránce nejsou vidět. Některé z nich se občas objeví:

Jak je uvedeno výše, způsob reprezentace nových řádků závisí na platformě, což je z historických důvodů nešťastné. V Pythonu se tím však obvykle nemusíme zabývat: při čtení textového souboru Python převede libovolnou sekvenci nového řádku na '\n'. Při zápisu naopak převede '\n' na sekvenci odpovídající operačnímu systému, například ve Windows na '\r\n'.

Novější znaková sada Unicode rozšiřuje ASCII o znaky všech jazyků světa, včetně znaků s diakritikou a ideografických znaků asijských jazyků, například 日. Kódové body Unicode jsou v rozsahu 0 až 1 114 111.

Velkou tabulku existujících znaků Unicode najdete na webu symbl.cc.

Stejně jako většina moderních programovacích jazyků je Python s Unicode plně kompatibilní. Můžete napsat například:

    s = 'Řehoř'

nebo

    s = '人'

a tyto řetězce budou fungovat stejně jako řetězce obsahující znaky ASCII.

chr() a ord()

Python obsahuje dvě funkce, které převádějí mezi znaky a jejich celočíselnými kódovými body.

Pro znak Unicode c vrátí ord(c) jeho kódový bod. Například ord('A') je 65, ord('B') je 66 a ord('ř') je 345, což je hodnota mimo rozsah ASCII.

Funkce chr() funguje opačně: převede kódový bod na znak. Například chr(65) je 'A' a chr(345) je 'ř'.

Tyto funkce se někdy hodí při manipulaci se znaky. Následující program například načte malé písmeno a vypíše následující písmeno abecedy:

    c = input('enter letter: ')
    i = ord(c) - ord('a')
    if 0 <= i < 26:
        i = (i + 1) % 26
        print('next letter is', chr(ord('a') + i))
    else:
        print('not a lowercase letter')

Program používá ord() k převodu znaku (například 'd') na číslo (například 3), které představuje jeho pozici v abecedě malých písmen. Poté přičte 1 modulo 26 a pomocí chr() převede výsledek zpět na malé písmeno.

Další informace o řetězcích

Podívejme se na další operace s řetězci v Pythonu. Funkce len() vrací délku řetězce:

    >>> len('zmrzlina')
    8

Operátorem [] můžeme z řetězce s získat jednotlivé znaky. První znak je s[0], druhý s[1] atd.:

    >>> s = 'zmrzlina'
    >>> s[0]
    'z'
    >>> s[1]
    'm'

Číslo v hranatých závorkách (například 0 nebo 1 výše) se nazývá index. V Pythonu záporný index získá znak od konce řetězce. Například s[-1] je poslední znak a s[-2] předposlední:

    >>> s[-1]
    'a'
    >>> s[-2]
    'n'

Řetězce v Pythonu jsou neměnné (immutable), což znamená, že je nelze měnit. Znaky řetězce tedy nemůžete přepisovat:

    >>> s = 'watermelon'
    >>> s[2] = 'x'
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: 'str' object does not support item assignment

Vestavěný operátor in lze použít také u řetězců. Pokud jsou s a t řetězce, výraz s in t ověřuje, zda je s podřetězcem řetězce t:

    >>> 'water' in 'watermelon'
    True
    >>> 'melon' in 'watermelon'
    True
    >>> 'xyz' in 'watermelon'
    False

Výřezy řetězců

Syntaxe s[i : j] vrací výřez (tedy podřetězec) obsahující prvky od s[i] až po prvek před s[j]. Index i i j může být záporný, což znamená indexování od konce sekvence:

    >>> s = 'watermelon'
    >>> s[0:5]
    'water'
    >>> s[2:5]
    'ter'
    >>> s[5:-1]
    'melo'
    >>> s[-3:-1]
    'lo'

Pokud v zápisu s[i : j] vynecháte počáteční index i, použije se 0, tedy začátek řetězce. Pokud vynecháte koncový index j, použije se len(s), tedy konec řetězce:

    >>> s[:5]
    'water'
    >>> s[5:]
    'melon'

Syntaxe s[i : j : k] vytvoří výřez znaků, při kterém se index v každém kroku posune o k. Pokud například použijeme k = 2, získáme znaky ob jeden:

    >>> s[0:8:2]
    'wtre'

Hodnota kroku může být i záporná:

    >>> s[6:2:-1]
    'emre'

Je-li krok záporný, vynechaný počáteční index znamená konec řetězce a vynechaný koncový index jeho začátek:

    >>> s[:4:-1]
    'nolem'
    >>> s[4::-1]
    'retaw'

Řetězec můžete obrátit zadáním kroku -1 a vynecháním počátečního i koncového indexu:

    >>> s[::-1]
    'nolemretaw'