Feedback

Umístění importů

Importy se píšou na začátku souboru. Tuto konvenci používají všichny Python programátoři. Psát je kdekoli jinde není chyba, která by způsobila nefunkčnost programu, ale může způsobit, že:

  • se bude import špatně hledat při čtení kódu a pátrání "odkud se tato funkce vzala"
  • bude třeba provést stejný import na více místech, protože importovaná funkce bude použita vícekrát

Existují totiž tři možnosti, jak se funkce v programu objeví:

  • Funkce dostupná automaticky - tyhle funkce každý zná, protože jich není mnoho. Konkrétně jsou vyjmenovány v dokumentaci.
  • Funkce je v tom samém souboru definována - ty se hledají celkem snadno, dokud soubor nemá tisíce řádků
  • Funkce je odněkud importovaná a protože import je celkem snadno přehlédnutelný, dává se na začátek souboru.

Špatně

In [1]:
def odmocnina(x):
    from math import sqrt
    return sqrt(x)

Správně

In [2]:
from math import sqrt

def odmocnina(x):
    return sqrt(x)

Diakritika a konzistentnost

Pokud program používá diakritiku, měl by v tomto být konzistentní. Pokud tedy používám diakritiku ve výstupech uživateli, měl bych počítat i s tím, že ji uživatel použije při zadávání svého jména. Tento program s tím nepočítá, protože klasická česká ženská jména končící na á označí za mužská.

In [3]:
jmeno = input("Zadej jméno: ")
if jmeno[-1] == "a": # na většinu jmen to stačí :)
    print("Jsi žena!")
elif jmeno[-1] == "e":
    print("Jsi žena!")
else:
    print("Jsi muž!")
Zadej jmeno: Nováková
Jsi muž!

Pokud funkce něco dělá, ale nevrací žádnou hodnotu, je zbytečné ji volat uvnitř funkce print. Stačí ji zavolat samostatně.

Pokud totiž funkce nic nevrací (přesněji vrací None), print nám to vypíše a uživateli to nebude dávat smysl.

Funkce pro vykreslení domečku

In [5]:
from turtle import forward, left

def domecek(n):
    for i in range(4):
        forward(n)
        left(90)
    left(45)
    forward(sqrt(2)*n)
    left(90)
    forward((sqrt(2)*n)/2)
    left(90)
    forward((sqrt(2)*n)/2)
    left(90)
    forward(sqrt(2)*n)
    left(45)
    forward(30)

Volání se zbytečnými printy

In [7]:
print(domecek(10))
print(domecek(20))
print(domecek(40))
None
None
None

Jednodušší varianta

In [12]:
domecek(10)
domecek(20)
domecek(40)

Najdi chybu

In [14]:
tah_pocitace = 'kámen'
tah_cloveka = ''

while tah_cloveka!="konec":
    tah_cloveka = input('kámen, nůžky, nebo papír? Pokud nechceš hrát napiš konec:')
    if tah_cloveka == 'kámen':
        if tah_pocitace == 'kámen':
            print('Plichta.')
        elif tah_pocitace == 'nůžky':
            print('Vyhrála jsi!')
        elif tah_pocitace == 'papír':
            print('Počítač vyhrál.')
    elif tah_cloveka == 'nůžky':
        if tah_pocitace == 'kámen':
            print('Počítač vyhrál.')
        elif tah_pocitace == 'nůžky':
            print('Plichta.')
        elif tah_pocitace == 'papír':
            print('Vyhrála jsi!')
    elif tah_cloveka == 'papír':
        if tah_pocitace == 'kámen':
            print('Vyhrála jsi!')
        elif tah_pocitace == 'nůžky':
            print('Počítač vyhrál.')
        elif tah_pocitace == 'papír':
            print('Plichta.')
    else:
        print('Nerozumím.')
kámen, nůžky, nebo papír? Pokud nechceš hrát napiš konec:nůžky
Počítač vyhrál.
kámen, nůžky, nebo papír? Pokud nechceš hrát napiš konec:papír
Vyhrála jsi!
kámen, nůžky, nebo papír? Pokud nechceš hrát napiš konec:konec
Nerozumím.

Prázdné tělo

Špatně

Funkce i cyklus musí vždy obsahovat alespoň něco. U funkcí to může být třeba jen dokumentační řetězec, ale něco tam být musí. Pokud přeci jen chceme nechat funkci nebo cyklus bez obsahu, existuje k tomu speciální klíčové slovo pass.

In [20]:
def testovaci_funkce():
  File "<ipython-input-20-d63ba48a78c0>", line 1
    def testovaci_funkce():
                           ^
SyntaxError: unexpected EOF while parsing
In [21]:
while True:
  File "<ipython-input-21-892b78802dca>", line 1
    while True:
               ^
SyntaxError: unexpected EOF while parsing

Správně

In [14]:
def testovaci_funkce():
    pass
In [ ]:
while True:
    pass

Tři funkce pro hada

Je zbytečné funkcím předávat něco, co si mohou samy vypočítat. Ještě horší to je, pokud by se používané hodnoty měly mezi jednotlivými voláními měnit.

Neměnné globální proměnné (nejhorší možnost)

In [33]:
n = 5
strana = 200/n
uhel = 360/n

def uhelnik(n):
    for x in range(n):
        forward(strana)
        left(uhel)
    forward(100)

uhelnik(5)
uhelnik(8)

Globální proměnné počítané před funkcí a předávané jako parametry (středně špatná možnost)

In [37]:
def uhelnik(n, delka_strany, uhel_otoceni):
    for x in range(n):
        forward(delka_strany)
        left(uhel_otoceni)
    forward(100)

n = 5
strana = 200/n
uhel = 360/n

uhelnik(n, strana, uhel)

n = 8
strana = 200/n
uhel = 360/n

uhelnik(n, strana, uhel)

Výpočet uvnitř funkce (nejlepší možnost)

In [39]:
def uhelnik(n):
    delka_strany = 200 / n
    uhel_otoceni = 360 / n
    
    for x in range(n):
        forward(delka_strany)
        left(uhel_otoceni)
    forward(100)

uhelnik(5)
uhelnik(8)
uhelnik(10)

Nespuštěná jakoby nebyla

In [1]:
from math import sqrt

def odmocnina(x):
    return sqrt(x)
In [2]:
odmocnina(4096)
Out[2]:
64.0

OTAZKA: jde nejak pouzit promenou bez toho abych ji musela posilat jako parametry funkce, ale abych ji mohla definovat mimo funkci?

Tato otázka byla u úkolu, kde to nebylo potřeba,

In [6]:
from random import randrange

def hazej(hrac):
    pocet_hodu = 0
    print('Hazi hrac cislo', hrac)
    while True:
        pocet_hodu += 1
        hod = randrange(1, 7)
        print('Hrac ', hrac, ' hodil ', hod)
        if hod == 6:
            break
    return pocet_hodu

vyherce = 0
vyherce_pokusu = 0

for hrac in range(1, 6):
    pokusu = hazej(hrac)
    if pokusu > vyherce_pokusu:
        vyherce_pokusu = pokusu
        vyherce = hrac

print('Vyhral hrac cislo ', vyherce, ' ktery potreboval', vyherce_pokusu, ' hodu')
    
Hazi hrac cislo 1
Hrac  1  hodil  6
Hazi hrac cislo 2
Hrac  2  hodil  5
Hrac  2  hodil  3
Hrac  2  hodil  2
Hrac  2  hodil  3
Hrac  2  hodil  2
Hrac  2  hodil  4
Hrac  2  hodil  1
Hrac  2  hodil  3
Hrac  2  hodil  6
Hazi hrac cislo 3
Hrac  3  hodil  2
Hrac  3  hodil  4
Hrac  3  hodil  5
Hrac  3  hodil  1
Hrac  3  hodil  3
Hrac  3  hodil  4
Hrac  3  hodil  3
Hrac  3  hodil  2
Hrac  3  hodil  5
Hrac  3  hodil  5
Hrac  3  hodil  1
Hrac  3  hodil  4
Hrac  3  hodil  4
Hrac  3  hodil  1
Hrac  3  hodil  6
Hazi hrac cislo 4
Hrac  4  hodil  5
Hrac  4  hodil  4
Hrac  4  hodil  5
Hrac  4  hodil  5
Hrac  4  hodil  3
Hrac  4  hodil  3
Hrac  4  hodil  1
Hrac  4  hodil  4
Hrac  4  hodil  6
Hazi hrac cislo 5
Hrac  5  hodil  4
Hrac  5  hodil  3
Hrac  5  hodil  3
Hrac  5  hodil  3
Hrac  5  hodil  3
Hrac  5  hodil  6
Vyhral hrac cislo  3  ktery potreboval 15  hodu

Odpověď: Ne, ale ...

z funkce lze vrátit více než jednu hodnotu

In [ ]:
def obvod_obsah_ctverce(a):
    obvod = 4 * a
    obsah = a * a
    return obvod, obsah
In [ ]:
obvod, obsah = obvod_obsah_ctverce(5)
print('Obvod je', obvod, 'cm. Obsah je', obsah, 'cm2.')

Obecné

  • Zkontrolovat před odesláním, že program dělá to, co dělat má

Piškvorky

In [1]:
from random import randrange

znak_hrace = 'X'
znak_pocitace = 'O'


def tah(herni_pole, pozice, znak):
    return herni_pole[:pozice] + znak + herni_pole[pozice + 1:]


def tah_hrace(herni_pole):
    while True:
        pozice = int(input('Zadej, kam chceš hrát: '))

        if pozice < 0 or pozice > len(herni_pole):
            print('Drž se v rozumných mezích!')
            continue
        if herni_pole[pozice] != '-':
            print('Toto pole už je obsazené!')
            continue

        return tah(herni_pole, pozice, znak_hrace)


def tah_pocitace(herni_pole):
    while True:
        pozice = randrange(0, 20)

        if herni_pole[pozice] != '-':
            continue

        return tah(herni_pole, pozice, znak_pocitace)


def vyhodnot(herni_pole):
    if 'XXX' in herni_pole:
        return 'X'
    elif 'OOO' in herni_pole:
        return 'O'
    elif '-' not in herni_pole:
        return '!'
    else:
        return '-'


def piskvorky1d():
    pole = '-' * 20

    while True:
        print('Hrací pole: ', pole)

        pole = tah_hrace(pole)
        vyhodnoceni = vyhodnot(pole)
        if vyhodnoceni != '-':
            break

        pole = tah_pocitace(pole)
        vyhodnoceni = vyhodnot(pole)
        if vyhodnoceni != '-':
            break

    print('Finální hrací pole: ', pole)
    if vyhodnoceni == 'X':
        print('Vyhrál jsi!')
    elif vyhodnoceni == 'O':
        print('Vyhrál počítač')
    else:
        print('Došlo k remíze')


piskvorky1d()
Hrací pole:  --------------------
Zadej, kam chceš hrát: 5
Hrací pole:  -----X------------O-
Zadej, kam chceš hrát: 7
Hrací pole:  -----X-X---------OO-
Zadej, kam chceš hrát: 3
Hrací pole:  ---X-X-X-------O-OO-
Zadej, kam chceš hrát: 4
Finální hrací pole:  ---XXX-X-------O-OO-
Vyhrál jsi!