Cvičení č. 3 rozšířené o poznámky ze cvičení a řešení některých příkladů (ZS 2025/26)¶

  • Jak efektivně psát na klávesnici – určitě všichni ovládáme nebo alespoň procvičujeme psaní všemi deseti 😃
  • Jak jsou kódovaná data v paměti počítače
  • Jak zadávat číselné hodnoty – převod textu získaného pomocí funkce input na číslo

Funkce input vždy vrátí textový objekt, i když uživatel zadá číslo. Pokud chceme získat číselný objekt, musíme použít příslušnou funkci, která získá číselnou hodnotu z textu:

  • funkce int vrátí celé číslo:
    a = int(input("Zadej celé číslo:"))
    
  • funkce float vrátí "reálné" číslo:
    a = float(input("Zadej libovolné reálné číslo:"))
    

Navíc: příklad z minule¶

  1. Napište program, který se zeptá uživatele na kladné číslo a spočítá obvod a obsah čtverce, který má délku strany rovnou zadané hodnotě.
In [3]:
# je dobré si to rozdělit na 3 části: načíst zadání, spočítat výsledek, vypsat výsledek
a = input("Zadej délku strany:")
a = float(a) 
# mohu zkratit na jeden řádek:
#a = float(input("Zadej délku strany:"))

o = 4 * a
s = a * a

print("Obvod čtverce o délce strany", a, "je", o,"a jeho obsah je", s,".")
Obvod čtverce o délce strany 4.0 je 16.0 a jeho obsah je 16.0 .
In [4]:
# pro pokročilé:
print(f"Obvod čtverce o délce strany {a} je {o} a jeho obsah je {s:.2f}.")
Obvod čtverce o délce strany 4.0 je 16.0 a jeho obsah je 16.00.

Datové typy a zápis hodnot v Pythonu¶

V této sekci si ukážeme použití základních aritmetických typů v jazyku Python (bool, int, float, complex), podporované operátory a převod mezi různými typy. Naopak práci s textovými řetězci (typ str) odložíme na později.

In [1]:
# každá hodnota nebo proměnná má nějaký datový typ (např. `bool`, `int`, `float`, `str`)
# typ proměnné interpret určí automaticky
# abychom zjistili, jakého je nějaká proměnná typu, můžeme použít funkce `type` a `isinstance`
a = 5
print (a, "je typu", type(a))
b = 5.3
print (b, "je typu", type(b))
c = "5"
print (c, "je typu", type(c))
d = True
print (d, "je typu", type(d))
type(d)
5 je typu <class 'int'>
5.3 je typu <class 'float'>
5 je typu <class 'str'>
True je typu <class 'bool'>
Out[1]:
bool
In [3]:
a = 10 > 3
print(a)
type(a)
True
Out[3]:
bool
In [10]:
a = 5 / 7
type(a)
Out[10]:
float

Typ bool a speciální hodnota None¶

Typ bool je datový typ umožňující reprezentovat pravdivostní hodnoty pravda (true) a nepravda (false), které se v jazyku Python zapisují pomocí konstant True a False (pozor na velká písmena!). Dále je možné použít funkci bool pro převod jiných datových typů a používat logické operátory and, or, not:

In [7]:
# definice proměnné typu bool
a = True
b = False
print(a, b)
not (a or b) # operátory and, or, not
True False
Out[7]:
False
In [6]:
b = a and (not a or True)
print(b)
True False
True
In [9]:
# na bool mohu převádět jiné datové typy:
# 0 nebo 0.0     -> False
# nenulové číslo -> True

# prázdný string             -> False
# jakýkoliv neprázdný string -> True

print(bool(0),  bool(0.0),  bool(""))
print(bool(-1), bool(-1.0), bool("O"))
False False False
True True True
In [13]:
# převod z bool na int nebo float:
a = True
x = float(a)
y = int(a)
z = str(a)
print(x, y, z)
1.0 1 True
In [3]:
a = True
b = 0
print(a and not bool(b))
True
In [ ]:
# operátory porovnání: == , != , < , > , >= , <=
In [14]:
x = 4.0
y = 4
x == y
Out[14]:
True
In [26]:
x = 10
y = 4
print(x > y, x < y, x >= y, x <= y, x == y, x != y)
print ( (x > y) and not (y > 1))
True False True False False True
False
In [29]:
x == y
Out[29]:
True
In [28]:
x = y
In [34]:
b = True
c = False
print(int(b), int(c), float(b), str(b))
1 0 1.0 True
In [35]:
str(b)
Out[35]:
'True'
In [37]:
bool('False')
Out[37]:
True

K zamyšlení a vyzkoušení: jaké další operátory jsou v Pythonu k dispozici pro hodnoty typu bool?

V jazyku Python existuje další hodnota reprezentovaná konstantou None, která představuje "prázdnou" hodnotu. Lze ji použít např. pro inicializaci proměnné, kterou budeme dále v programu potřebovat, ale zatím pro ni nemáme žádnou užitečnou hodnotu. Hodnota None také může sloužit k zavedení ternární logiky v programu, ale na rozdíl od hodnot True a False má svůj vlastní typ (ne bool ani int, ale NoneType).

In [16]:
# speciální hodnota None ... pro "prázdnou" hodnotu (typu NoneType)
x = None
print(x)
type(x)
None
Out[16]:
NoneType
In [18]:
# funkce print vrací hodnotu None:
x = print("ahoj")
print(x)
type(x)
ahoj
None
Out[18]:
NoneType
In [19]:
x

Typ int¶

Typ int je datový typ pro reprezentaci celých čísel. Přípustné hodnoty jsou např. 0, 1, 2, 3, ..., a dále -1, -2, -3, ... Celá čísla se ve zdrojovém kódu jazyka Python běžně zadávají v desítkové soustavě, jako např.:

In [41]:
a = 123456789
print(a, type(a))
123456789 <class 'int'>

Omezení na zápis celých čísel ve zdrojovém kódu jsou v zásadě dvě: číselný zápis nesmí začínat nulou a mezi číslicemi nesmí být mezery:

In [42]:
a = 01
  Cell In[42], line 1
    a = 01
        ^
SyntaxError: leading zeros in decimal integer literals are not permitted; use an 0o prefix for octal integers
In [43]:
a = 123 456
  Cell In[43], line 1
    a = 123 456
            ^
SyntaxError: invalid syntax

Naopak mezi číslicemi může vystupovat znak _, který slouží jako oddělovač pro člověka významných číslic, podobně jako např. mezery v zápisu telefonního čísla. Jakýkoliv výskyt znaku _ však nezmění číselnou hodnotu.

In [46]:
print(2_123_456)
print(77_888_8_99)
2123456
77888899

Zápis čísel v jiných soustavách¶

Kromě desítkové soustavy lze pro zápis čísel v jazyku Python použít také dvojkovou (binární), osmičkovou nebo šestnáctkovou (hexadecimální) soustavu. Pro odlišení od desítkového zápisu se používají prefixy 0b, 0o a 0x, za kterými následují číslice příslušné soustavy, přičemž první číslice za prefixem může být 0:

  • dvojková: 0b01
  • osmičková: 0o01234567
  • šestnáctková: 0x0123456789abcdef

V libovolné soustavě také můžeme použít oddělovač číslic _ pro zlepšení čitelnosti kódu, např.:

In [47]:
print(0b1011000_10101011)
22699

Všimněte si, že rozlišení číselných soustav vystupuje pouze na úrovni zdrojového kódu. Jak bylo řečeno, interně program pracuje vždy se dvojkovou soustavou. Naopak pro výstup jazyk Python používá desítkovou reprezentaci dané hodnoty (pokud mu neřekneme jinak):

In [48]:
print(11)
print(0o11)
print(0x11)
print(0b11)
11
9
17
3
In [23]:
# uměli byste sami převést číslo do desítkové soustavy?
0b101
Out[23]:
5
In [26]:
0o72
Out[26]:
58
In [25]:
0o101
Out[25]:
65
In [54]:
0x101
Out[54]:
257
In [24]:
0xA2
Out[24]:
162

Pokud chceme vytisknout reprezentaci čísla v jiné soustavě než desítkové, můžeme použít některou z funkcí bin, oct a hex:

In [56]:
print(bin(10), oct(10), hex(10))
0b1010 0o12 0xa
In [27]:
# pozor, fce bin, oct, dec, vrací textový řetězec, ne číslo
type(bin(10))
Out[27]:
str
In [55]:
print(bin(11))
print(oct(0x11))
print(hex(0b1111))
0b1011
0o21
0xf

Všechny tři funkce však vrací textový řetězec (typ str, na který se podrobně podíváme později), ale jako vstup očekávají číslo (typ int). Nelze je tedy skládat, např. výrazy jako hex(bin(1)) nebo oct(hex(1)) nebudou fungovat.

In [29]:
# nefunguje:
hex(bin(1))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[29], line 2
      1 # nefunguje:
----> 2 hex(bin(1))

TypeError: 'str' object cannot be interpreted as an integer

Aritmetické operátory¶

S číselnými hodnotami můžeme provádět různé aritmetické operace. V Pythonu jsou k dispozici tyto aritmetické operátory:

Operace Výsledek
x + y součet hodnot $x$ a $y$
x - y rozdíl hodnot $x$ a $y$
x * y součin hodnot $x$ a $y$
x / y podíl hodnot $x$ a $y$
x // y celočíselný podíl hodnot $x$ a $y$
x % y zbytek po celočíselném dělení hodnot $x$ a $y$
-x hodnota $-x$
+x hodnota $x$
x ** y $x^y$ ($x$ "na" $y$)

Jak uvidíme na dalších cvičeních, některé z těchto operátorů lze použít i pro hodnoty nečíselných typů, kde ale mají jiný význam.

In [61]:
# příklad na unární plus
6 * +5
Out[61]:
30
In [31]:
# příklad na unární minus 
x = 67
6 * -x
Out[31]:
-402
In [63]:
6 // 5 
Out[63]:
1

Příklad¶

Přesný čas

  • Napište program, který zadaný čas ve vteřinách vypíše v hodinách, minutách a vteřinách. Případně i ve dnech a rocích.
  • Napište program, který zadaný čas ve dnech, hodinách, minutách a vteřinách vypíše ve vteřinách.
In [32]:
# 125 vteřin .. 0 hodin, 2 minuty a 5 vteřin
celkem_vterin = int(input("Zadej počet vteřin"))

# nejprve jen rozdělím na minuty a vteřiny
celkem_minut = celkem_vterin // 60
zbylych_vterin = celkem_vterin - celkem_minut * 60 # celkový čas ve vteřinách rozdělím na celé minuty a zbylé vteřiny   
zbylych_vterin = celkem_vterin % 60                # alternativně


print("Výsledek je", celkem_minut, "minut a",  zbylych_vterin, "vteřin.")
Výsledek je 2 minut a 5 vteřin.
In [34]:
# 125 vteřin .. 0 hodin, 2 minuty a 5 vteřin
celkem_vterin = int(input("Zadej počet vteřin"))

celkem_minut = celkem_vterin // 60
zbylych_vterin = celkem_vterin % 60

celkem_hodin = celkem_minut // 60
zbylych_minut = celkem_minut % 60

celkem_dnů = celkem_hodin // 24
zbylych_hodin = celkem_hodin % 24

# obdobně pro roky ... dělím 365

print("Výsledek je", celkem_dnů, "dnů", zbylych_hodin, "hodin", zbylych_minut, "minut a",  zbylych_vterin, "vteřin.")
Výsledek je 0 dnů 1 hodin 49 minut a 8 vteřin.
In [36]:
vteřin = int(input("Zadej počet vteřin"))
minut = int(input("Zadej počet minut"))
hodin =  int(input("Zadej počet hodin"))
dnu =  int(input("Zadej počet dnů"))
roku = int(input("Zadej počet roků"))

# typické řešení:
celkem = vteřin + 60*minut + 60*60*hodin + 60*60*24*dnu + 60*60*24*365*roku 
print("Celkem", celkem, "vteřin.")                      
Celkem 94614548 vteřin.

Typ float¶

Typ float je datový typ pro reprezentaci "reálných" čísel. Tyto hodnoty můžeme ve zdrojovém kódu zapsat pomocí běžného zápisu s desetinnou tečkou, např. 1.5, 2.0 nebo 2. (výraz 2. je ekvivalentní 2.0 a je různý od 2). Stejně jako v případě celých čísel i pro hodnoty typu float můžeme používat oddělovač _, a to jak před desetinnou tečkou, tak i za ní:

In [71]:
x = 2.3
print(x, type(x))
2.3 <class 'float'>
In [73]:
x = .5
x
Out[73]:
0.5
In [76]:
x = 5.
x
Out[76]:
5.0
In [11]:
print(1_234.567_8)   # libovolně mohu prokládat _
1234.5678

Kromě zápisu v klasickém tvaru s desetinnou tečkou můžeme pro zápis "reálných" čísel použít tzv. exponentový tvar, ve kterém použijeme písmeno e nebo E, za něž zapíšeme číslo oznamující, kolikátou mocninou deseti se má vynásobit číslo zadané vlevo od znaku e, resp. E. Python tento tvar používá také v některých případech pro výpis:

In [38]:
# exponentový tvar: s e/E (číslo násobíme mocninami deseti)
print(123e-3)
print(123e3)

# exponentový tvar bude i u výpisu:
print(123_456_789_0_123_456_789_0_123_456_789.)
print(1/10000000000)
0.123
123000.0
1.2345678901234568e+28
1e-10

Všimněte si, že při výpisu posledního čísla Python nevypsal všechny číslice, které se vyskytují v zápisu čísla ve zdrojovém kódu. To ale neznamená, že s nimi program nepracuje. Při převodu desetinného čísla do dvojkové soustavy a uložení v paměti počítače sice může dojít k zaokrouhlení, ale k dalšímu zaokrouhlení s ještě menší přesností dochází při výpisu čísla v desítkové soustavě. Toto chování je kvůli pohodlí uživatele. Později si ukážeme, jak ovlivnit přesnost vypisovaných čísel.

In [39]:
# k převodu z int na float někdy dojde automaticky při aritmetických operacích:
4 / 4
Out[39]:
1.0
In [79]:
5.0 + 6
Out[79]:
11.0
In [41]:
x = 4
x * 1.
Out[41]:
4.0
In [86]:
# k převodu mezi int a float mohu použít funkce `int` a `float`
float(4)
Out[86]:
4.0
In [43]:
int(3.6)   # zaokrouhlí vždy k 0
Out[43]:
3
In [44]:
int(-3.6)   # zaokrouhlí vždy k 0
Out[44]:
-3
In [88]:
float(True)
Out[88]:
1.0
In [89]:
float("1.3")
Out[89]:
1.3
In [42]:
float('3.78e2')
Out[42]:
378.0

S hodnotami typu float můžeme provádět všechny aritmetické operace stejně jako pro typ int, viz tabulka výše.

K zamyšlení a vyzkoušení: jak funguje celočíselné dělení pro necelá čísla?

In [94]:
430. / 10.
Out[94]:
43.0
In [46]:
# zaokrouhlovací chyba:
4.3 / 0.1 #== 43
Out[46]:
42.99999999999999
In [45]:
print(432.1 // 10, 432.1 % 10)
43.0 2.1000000000000227
In [93]:
print(4.321 // 0.1, 4.321 % 0.1)
43.0 0.02099999999999949

Číselné hodnoty můžeme v programu převádět z typu int na typ float a opačně. Explicitní převod typu pro danou hodnotu vyvoláme, pokud int nebo float použijeme jako funkci:

In [13]:
print(int(1.5))
print(float(2))
1
2.0

K převodu typu může dojít také implicitně, např. pokud sčítáme hodnotu typu int s hodnotou typu float, přičemž výsledek bude "většího" typu float.

Všimněte si, že funkce int zaokrouhluje vždy směrem dolů, tj. odsekne a zahodí desetinnou část daného čísla. Pokud chceme zaokrouhlení směrem k nejbližšímu celému číslu, poslouží nám funkce round:

In [85]:
print(round(-1.5))
-2

Matematické funkce a konstanty¶

Kromě aritmetických operátorů je často potřeba při práci s číselnými hodnotami použít nějakou matematickou funkci. Nejzákladnější funkce abs, min a max jsou v jazyku Python k dispozici přímo. Poznamenejme, že funkce min a max mají dva nebo více číselných parametrů a funkce abs má jeden číselný parametr.

In [101]:
a = -1.4
b = 2.8
c = min(a, b)
d = max(a, b, c)
e = abs(d) 
print(c, d, e)
-1.4 2.8 2.8

Další matematické funkce jako např. sqrt (odmocnina), sin nebo cos nejsou k dispozici přímo, ale v tzv. modulu. Moduly jsou v jazyku Python ucelené části zdrojového kódu, které obsahují proměnné, funkce a další objekty. V první řadě je potřeba říci, že Python poskytuje širokou standardní knihovnu složenou z mnoha modulů, které programátorům usnadňují život. Jeden z takových modulů je modul math obsahující matematické funkce a konstanty.

Abychom obsah modulu zpřístupnili, musíme jej nejprve importovat pomocí příkazu import. K objektům v modulu se potom dostaneme pomocí tečkové notace:

In [48]:
import math

print("Číslo π je přibližně", math.pi)
print("Hodnota cos(π) je ", math.cos(math.pi))

pi = 3.14
print("Číslo π je přibližně", pi)
print("Hodnota cos(π) je ", math.cos(pi))
Číslo π je přibližně 3.141592653589793
Hodnota cos(π) je  -1.0
Číslo π je přibližně 3.14
Hodnota cos(π) je  -0.9999987317275395
In [49]:
# jakmile provedu import, do restartu Kernelu mohu funkce a jiné objekty z modulu používat
print(math.exp(3))
20.085536923187668
In [50]:
math.e
Out[50]:
2.718281828459045

Alternativním způsobem importování je zápis from math import ..., kde místo ... napíšeme seznam identifikátorů, které chceme importovat, oddělených čárkami. Na rozdíl od předchozího způsobu pak nemusíme používat tečkovou notaci a importované objekty máme k dispozici přímo. Předchozí příklad tedy můžeme přepsat následovně:

In [5]:
from math import pi, cos

print("Číslo π je přibližně", pi)
print("Hodnota cos(π) je ", cos(pi))
Číslo π je přibližně 3.141592653589793
Hodnota cos(π) je  -1.0
In [11]:
pi = 3.14
print(pi)

from math import pi
print(pi)

pi = 3.14
print(pi)
3.14
3.141592653589793
3.14
In [52]:
cos = "ahoj"
print(cos)

from math import cos
print(cos)
print(cos(0))

cos = "ahoj"
print(cos)
ahoj
<built-in function cos>
1.0
ahoj

Místo seznamu identifikátorů můžeme z modulu importovat vše pomocí příkazu from math import *. To nám ušetří práci s psaním dlouhého seznamu názvů, ale na druhou stranu se tím zvýší pravděpodobnost kolize mezi názvy importovaných objektů a námi definovaných proměnných a funkcí.

In [53]:
from math import * # NEPOUŽÍVAT !!!!

print(pi, e, inf)
3.141592653589793 2.718281828459045 inf

K tématu modulů se během semestru ještě několikrát vrátíme. Naučíme se používat další funkce a třídy dostupné v modulech standardní knihovny a také se naučíme tvořit vlastní moduly pro přehlednější strukturování vlastního programu.

Příklady¶

  1. Napište program, který se uživatele zeptá na jeho hmotnost a pomocí průměrné hustoty lidského těla ($1000~kg/m^3$) spočítá jeho objem. Jaký by měl uživatel průměr, pokud by měl tvar koule?
In [2]:
# 1. objem
hmotnost = float(input("zadej hmotnost cloveka"))
hustota = 1000

objem = hmotnost / hustota

print("Objem je", objem, "m^3.")
Objem je 0.06 m^3.
In [6]:
# 2. průměr
import math 

# koule: V = 4/3 Pi r^3
poloměr = (3 * objem / (4 * math.pi)) ** (1/3) # pozor na uzávorkování
průměr = 2 * poloměr

print("Průměr člověka-koule o objemu", objem, "m^3 je", průměr,  "m.") 
Průměr člověka-koule o objemu 0.06 m^3 je 0.4857180126010562 m.
  1. Objemy a povrchy geometrických těles
    • Napište program, který spočítá objem a povrch koule o průměru $d$, který zadá uživatel.
    • Napište program, který spočítá objem a povrch čtyřbokého jehlanu se základnou o straně délky $a$ a výškou délky $v$.
    • Napište program, který spočítá obvod a plochu pravidelného mnohoúhelníku o straně délky $a$.
In [ ]:
 
  1. Pravidelné mnohostěny Napište program, který spočítá objem a povrch pravidelného čtyřstěnu, krychle, pravidelného osmistěnu, pravidelného dvanáctistěnu a pravidelného dvacetistěnu.
In [ ]:
 
  1. Šitý fotbalový míč Napište program, který spočítá délku švů na fotbalovém míči tvaru komolého dvacetistěnu o poloměru $r$.
In [ ]:
 

Rozšíření nbgrader¶

V prostředí JupyterHub je nainstalované rozšíření nbgrader, které budeme používat pro zadávání a odevzdávání úkolů. Studentský pohled představuje nabídka Assignment List, kterou najdete v menu:

Po kliknutí se otevře nová záložka s nabídkou kurzů, ve kterých je přihlášený uživatel studentem. Dokud není zadaný žádný úkol, tento seznam je prázdný:

Také se objeví "no courses found", což však není chyba – znamená to, že zatím není zadaný žádný úkol. Po zadání prvního úkolu se v nabídce objeví název kurzu s aktuálním rokem: zpro2025.

Poznámka: Následující obrázky jsou z minulého roku, až na jiný obsah je však rozvržení všech prvků stejné.

Po zveřejnění nového úkolu se objeví další položka v seznamu "Released assignments":

Kliknutím na tlačítko "Fetch" se stáhnou soubory pro daný úkol do vašeho domovského adresáře a objeví se příslušná položka v seznamu "Downloaded assignments":

Klikněte na název úkolu (viz červený rámeček výše) a poté na název souboru (o řádek níže, viz červený rámeček na dalším obrázku):

Tím se v nové záložce otevře Jupyter notebook se zadáním úkolu, který může vypadat např. takto:

V zadání je typicky několik buněk, které byste neměli měnit. Buňka, ve které je potřeba vypracovat zadaný úkol, je označena komentářem YOUR CODE HERE. V tomto ukázkovém příkladu je potřeba nahradit celý obsah buňky, v budoucích úkolech však může být předpřipravený kód, který je potřeba dokončit.

Poznámka: První úkol obsahuje podrobnější návod k použití před samotným zadáním.

Při programování úkolu můžete využít tlačítko "Validate", kterým se spustí kontrola testů, které byly zveřejněny spolu s úkolem. Dále může úkol obsahovat skryté testy, které studenti nevidí, ale provedou se při kontrole úkolu vyučujícím.

Jakmile jste dostatečně spokojeni se svým řešením, zkontrolujte, že notebook s úkolem je uložený (stiskněte Ctrl+S). Poté přejděte zpět na záložku "Assignments", pro jistotu znovu použijte tlačítko "Validate" a odevzdejte úkol pomocí tlačítka "Submit":

Po odevzdání se objeví nová položka v seznamu "Submitted assignments" s časem odevzdání a tlačítko "Fetch Feedback", které v této chvíli nemá žádný efekt:

Teprve po zkontrolování úkolu vyučujícím a zveřejnění hodnocení, což může trvat několik dní, tlačítko "Fetch Feedback" stáhne report s ohodnoceným úkolem. Kliknutím na odkaz "view feedback" se v průzkumníku souborů nalevo zobrazí HTML soubor, který můžete otevřít a podívat se na své hodnocení.

Report obsahuje bodové ohodnocení buněk na základě vykonání automatických testů a případně také osobní vyjádření vyučujícího. Také se vám zobrazí kód skrytých testů, v této ukázce jsou však zastřeny:

Poznámky a omezení¶

  • Rozšíření nbgrader ve svém rozhraní neumožňuje studentům zobrazit deadline pro daný úkol. Datum tedy budeme ručně psát v textu samotného zadání.
  • Systém umožňuje opakované odevzdání úkolu. Před oznámkováním a zveřejněním výsledků to můžete využívat, výsledný report pak bude odpovídat poslední odevzdané verzi. Po oznámkování a zveřejnění výsledků se již oprava úkolu nijak neprojeví.