Cvičení č. 3 rozšířené o poznámky ze cvičení a řešení některých příkladů (ZS 2024/25)¶
V minulém díle jste viděli...¶
- 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:"))
# ukazovali jsme si řešení vybraných úkolů z minule
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.
# 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.0
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.0 je typu <class 'float'> 5 je typu <class 'str'> True je typu <class 'bool'>
bool
Typ bool
a speciální hodnota None
¶
# Logická (pravdivostní) hodnota (datový typ bool)
x = 3 # operátor přiřazení
x
3
x == 3 # operátor porovnání
True
# operátory porovnání: == , != , < , > , >= , <=
x != 3
False
print( x > 2, x < 10, x >= 2, x <= 1)
True True True False
# definice proměnné typu bool
a = True
b = False
a and (not a or b) # operátory and, or, not
False
# definice proměnné typu bool
a = True
b = a and not a
print(a)
print(b)
b = a and (not a or True)
print(b)
True False True
# abychom zjistili, jakého je nějaká proměnná typu, můžeme použít funkce `type` a `isinstance`
a = True
print(type(a))
type(a)
# výpis je v obou následujících příkladech trochu jiný, ale nemusíme se tím znepokojovat
<class 'bool'>
bool
x = 4
y = 7
x < y and y <= 10
True
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
:
# 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("cokoliv"))
False False False True True True
# převod z bool na int nebo float:
a = True
x = float(a)
y = int(a)
x
1.0
a = True
b = 0
print(a and not bool(b))
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
).
# speciální hodnota None ... pro "prázdnou" hodnotu (typu NoneType)
a = None
print(a)
print(type(a))
None <class 'NoneType'>
# funkce print vrací hodnotu None:
a = print("ahoj")
print(a)
print(type(a))
ahoj None <class 'NoneType'>
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ř.:
a = 123456789
print(a)
123456789
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:
a = 01
Cell In[25], line 1 a = 01 ^ SyntaxError: leading zeros in decimal integer literals are not permitted; use an 0o prefix for octal integers
a = 123 456
Cell In[6], 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.
print(123_456)
print(77_8888_99)
print(7_3_6)
123456 77888899 736
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
# uměli byste sami převést číslo do desítkové soustavy?
x = 0b11
x = 0b101
x
5
x = 0o72
# x = 0o101
x
58
x = 0xA2
#x = 0x101
x
162
V libovolné soustavě také můžeme použít oddělovač číslic _
pro zlepšení čitelnosti kódu, např.:
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):
# uměli byste sami převést číslo do desítkové soustavy?
print(11)
print(0o11)
print(0x11)
print(0b11)
11 9 17 3
Pokud chceme vytisknout reprezentaci čísla v jiné soustavě než desítkové, můžeme použít některou z funkcí bin
, oct
a hex
:
x = 0b101
#x = 120
print(x) # print vypíše číslo v desítkové soustavě
# výpis čísel v jiných soustavách:
print(bin(x), hex(x), oct(x))
5 0b101 0x5 0o5
'0b101'
# pozor, fce bin, oct, dec, vrací textový řetězec, ne číslo
x = 324
a = hex(x)
type(a)
str
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.
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.
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.
#celkový_čas = int(input("Zadej čas ve vteřinách:"))
celkový_čas = 315
celých_minut = celkový_čas // 60 # celkový čas ve vteřinách rozdělím na celé minuty a zbylé vteřiny
vteřin = celkový_čas % 60
print("Zadaný čas", celkový_čas, "vteřin =", celých_minut, "minut a", vteřin, "vteřin")
Zadaný čas 315 vteřin = 5 minut a 15 vteřin
#celkový_čas = int(input("Zadej čas ve vteřinách:"))
celkový_čas = 619965
celých_minut = celkový_čas // 60 # celkový čas ve vteřinách rozdělím na celé minuty a zbylé vteřiny
vteřin = celkový_čas % 60
celých_hodin = celých_minut // 60 # čas v minutách rozdělím na celé hodiny a zbylé minuty
minut = celých_minut % 60
celých_dnů = celých_hodin // 24 # čas v hodinách rozdělím na celé dny a zbylé hodiny
hodin = celých_hodin % 24
celých_let = celých_dnů // 365 # čas ve dnech rozdělím na celé roky a zbylé dny
dnů = celých_dnů % 365
print("Zadaný čas", celkový_čas, "vteřin =", celých_let, "roků,", dnů, "dnů,", hodin ,"hodin,", minut, "minut a",vteřin,"vteřin")
Zadaný čas 619965 vteřin = 0 roků, 7 dnů, 4 hodin, 12 minut a 45 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í:
x = 8.9
y = 8.0
z = 8. # totéž
u = 0.1
u = .1 # totéž
v = 1_163.567_453 # libovolně mohu prokládat _
print(x,y,z,u,v)
8.9 8.0 8.0 0.1 1163.567453
print(1_234.567_8)
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:
# 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/100000000)
# stejné aritmetické operace jako u int
0.123 123000.0 1.2345678901234568e+28 1e-08
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.
S hodnotami typu float
můžeme provádět všechny aritmetické operace stejně jako pro typ int
, viz tabulka výše.
# k převodu z int na float někdy dojde automaticky při aritmetických operacích:
4 / 3
1.3333333333333333
x = 4 + 0.1
print(x, type(x))
4.1 <class 'float'>
# k převodu mezi int a float mohu použít funkce `int` a `float`
x = 45
y = float(x)
print(x, y)
4.0
int(3.6) # zaokrouhlí vždy k 0
3
int(-3.6) # zaokrouhlí vždy k 0
-3
round(-3.6) # zaokrouhlí k nejbližšímu celému číslu
-4
K zamyšlení a vyzkoušení: jak funguje celočíselné dělení pro necelá čísla?
# tady to vypadá podle očekávání:
print(432.1 / 10)
print(432.1 // 10)
print(432.1 % 10)
43.21 43.0 2.1000000000000227
# tady to možná nevypadá podle očekávání:
print(4.321 / 0.10)
print(4.321 // 0.10)
print(4.321 % 0.10)
43.209999999999994 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:
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
:
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.
a = -1
b = 2
c = min(a, b)
d = max(a, b, c)
e = abs(d)
print(a, b, c, d, e)
-1 2 -1 2 2
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:
import math
pi = 3.14
print("Číslo π je přibližně", math.pi, pi)
print("Hodnota cos(π) je ", math.cos(math.pi), math.cos(pi))
print(math.e)
Číslo π je přibližně 3.141592653589793 3.14 Hodnota cos(π) je -1.0 -0.9999987317275395 2.718281828459045
# jakmile provedu import, do restartu Kernelu mohu funkce a jiné objekty z modulu používat
print(math.exp(3))
20.085536923187668
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ě:
from math import pi, cos
print("Číslo π je přibližně", pi)
print("Hodnota cos(π) je ", cos(pi))
# print(math.pi) # chyba
Číslo π je přibližně 3.141592653589793 Hodnota cos(π) je -1.0
# Import a proměnné
# už víme: hodnotu a typ proměnné můžeme měnit
x = 6
x = "ahoj"
x
'ahoj'
# podobně funguje i import:
pi = 3.15
cos = "ahoj"
print(pi, cos) # máme 2 proměnné pi a cos
from math import pi, cos # hodnoty proměnných pi a cos se změnily - nyní odkazují na objekty z modulu math
print("Číslo π je přibližně", pi)
print("Hodnota cos(π) je ", cos(pi))
print(cos) # již to nebude "ahoj", je to teď funkce
#print = ("ahoj") # častá začátečnická chyba ('=' na špatném místě)
3.15 ahoj Číslo π je přibližně 3.141592653589793 Hodnota cos(π) je -1.0 <built-in function cos>
# obrácený případ:
from math import pi, cos # hodnoty proměnných pi a cos odkazují na objekty z modulu math
pi = 3.14 # změním hodnotu pi
print("Číslo π je přibližně", pi)
print("Hodnota cos(π) je ", cos(pi))
Číslo π je přibližně 3.14 Hodnota cos(π) je -0.9999987317275395
from math import * # NEPOUŽÍVAT !!!!
print(pi, e, inf)
3.141592653589793 2.718281828459045 inf
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í.
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¶
- 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?
hmotnost = float(input("Zadejte svou hmotnost v kg:"))
hustota = 1000
objem = hmotnost / hustota
print("Váš objem je", objem, "m^3.")
Váš objem je 0.06 m^3.
from math import pi
# koule: V = 4/3 Pi r^3
poloměr = (3 * objem / (4 * pi)) ** (1/3)
průměr = 2 * poloměr
print("Průměr člověka-koule o objemu", objem, "m^3 je", 100*průměr, "cm.")
Průměr člověka-koule o objemu 0.06 m^3 je 48.571801260105616 cm.
- 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$.
- 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.
- Š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$.
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.
Název kurzu bude buď zpro2024
pro českou verzi nebo zpro2024-en
pro anglickou skupinu.
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.
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í.