print se všemi svými parametry a implicitními atributy má tuto skladbu:
print(objekty, sep="", end="\n", file=sys.stdout, flush=False)
Kromě prvního parametru "objekty" lze všechny další uvedené atributy vynechat, neboť to jsou pojmenované argumenty funkce:
>>> print("Ali" +"ba" *2)
Alibaba
Funkce print vyvolá vyhodnocení jednotlivých argumentů v závorkách:
>>> print("Je mi", 12 + 9, "let.") # (string, výraz, string)
Je mi 21 let. # fce print() odebrala apostrofy
Význam jednotlivých atributů je tento::
- sep = 'separátor' - určuje dělící znak mezi objekty:
>>> print(3,5,7, sep=", ")
3, 5, 7
- end = 'konec' - určuje poslední tisknutý znak nebo provedenou akci ('\n' je přechod na nový řádek:
>>> print(3,5,7, end="vsjo")
3 5 7 vsjo
>>> print("\n") # vytiskne 1 prázdný řádek
>>> print(3* "\n") # vytiskne 3 prázdné řádky
-
file - invokuje objekt s metodou 'write'; implicitně je to sys.stdout:
# 51_stdout.py
import sys
s = 'Python', 'je', 'bezvadný'
for e in s: # tisk na témže řádku
sys.stdout.write('\n')
for e in s: # každý element na jiném řádku
sys.stdout.write(e + '\n')
>>> %Run 51_stdout.py
Python je bezvadný
Python
je
bezvadný
-
flush - A Boolean, specifying if the output is flushed (True) or buffered (False). Default is False
Změnou argumentu end="\n" na end=" " lze zajistit pokračování tisku na témže řádku, přičemž rozestupem uvozovek lze ovlivnit rozestup mezi jednotlivými hodnotami výstupu.
Změnou argumentu sep="" lze přikázat typ oddělovače, případně vzdálenost mezi prvky entice - například sep=' ~ ':
>>> print('a', 'b', 'c', 'd')
a b c d
>>> print('a', 'b', 'c', 'd', sep=' ~ ', end=' !!')
a ~ b ~ c ~ d !!
Vhodné je také vědět, že příkaz k tisku funkce print() vrací None:
>>> print(print("Nazdar"))
Nazdar
None # Po výstupu "Nazdar" přišel na řadu příkaz print()
5.2 Příkaz return
Ve funkci s větvenými podmínkami s výhodou použijeme příkaz return:
def filtr(x):
if x <= 0:
return "Přirozené číslo, prosím"
return x
Protože jsou tyto příkazy v alternativních podmínkách, provedou se pouze jednou - jakmile se jeden z příkazů return provede, funkce
končí bez provádění následných příkazů.
Kód, který je zapsán za příkazem return i kterékoliv další místo, kam se tok programu nedostane,
se nazývá mrtvý kód.
Je dobré aby každá možná cesta funkcí narazila na příkaz
return. V následující verzi absolute_value toto zajištěno není:
def absolute_value(x):
if x < 0:
return -x
elif x > 0:
return x
Tato verze není zcela správná, protože bude-li x rovno nule, žádná z podmínek není
pravdivá a funkce končí, aniž by narazila na příkaz return; výslednou hodnotou je speciální
hodnota zvaná None typu NoneType:
>>> print(absolute_value(0))
None
Příkaz return se použije pouze uvnitř funkce, nikoliv mimo funkci a nikoliv uvnitř definice třídy.
Příkaz 'print' versus 'return'
Příkaz print má formát funkce a slouží k zobrazení zadaného obsahu uvnitř funkce i mimo funkci.
>>> print("Nazdárek Kašpárek") # použití mimo funkci
>>> def podíl(x, y): # použití uvnitř funkce
print(x / y)
>>> podíl(8, 3) # invokace funkce
2.6666666666666665
Příkaz return ukončí provádění funkce a vrátí vyhodnocený výraz (expression), je-li k dispozici. Není-li co vracet, vrací se implicitní hodnota "None".
Tato hodnota se však v shellu Pythonu či aplikace Thonny nezobrazuje. Chceme-li hodnotu None v shellu přesto zobrazit, použijeme příkaz print():
>>> def add_one(x): # funkce bez výstupu
result = x + 1
>>> add_one(8) # výstup "None" se nekoná
>>> print(add_one(8))
None # zde ano
5.3 Smyčka for
Smyčka for .. in si pro zadaný iterábl (viz 3.1) vytvoří vlastní iterátor, s nímž provádí iteraci po prvcích objektu:
for i in iterable: do something
st = {3.6, "cat", True} # kolekce typu set
for i in st:
print(i, end=" ")
>>> True 3.6 cat
Na výstupu idiomu for .. in vidíme, že pořadí elementů se změnilo, protože kolekce set pořadí změnit může, stejně jako kolekce frozenset.
Iterace slovníku (dict) vrací pouze klíče slovníku:
sl = {1: "uno", 2: "duo", 3: "tre"} # kolekce typu dict
for i in sl:
print(i, end=" ")
>>> 1 2 3
Případně:
sl = {1: "uno", 2: "duo", 3: "tre"} # kolekce typu dict
for i,j in sl.items(): # dict.items() je vestavěná methoda
print(i,j, end=" ")
>>> 1 uno 2 duo 3 tre
O tom, že naše kontejnery jsou vybaveny metodou __iter__ a že to tedy jsou iterábly, se přesvědčíme funkcí
dir(zkoumaný_objekt)
jejímž výstupem je seznam metod a funkcí zadaného objektu, v němž metodu __iter__ nalezneme.
Stejně jako smyčka for.. si vlastní iterátor vytvářejí funkce open(), min(), max(), map(), filter(), zip(), enumerate() a reversed().
Funkce open(...) s vlastním iterátorem:
>>> f = open("F:/Howtopy/files/week.txt") # iterátor pro week.txt
>>> next(f) # první řádek souboru
'pondělí\n'
>>> next(f) # další řádek souboru
'úterý\n'
>>> for i in f: print(i, end=" ") # zbývající řádky souboru
středa
čtvrtek
...
>>> f.close() # zavře soubor - viz kap.7.3
Následující příklad ukazuje použití zřetězení (concatenation) a smyčku for pro tvorbu
abecedních řad. Například, v knize Roberta McCloskeyho: Uvolněte cestu pro káčata se kachňata jmenují: Jack, Kack, Lack, Mack, Nack, Ouack, Pack a Quack. Tato smyčka vydá jejich jména v pořadí:
prefixes = "JKLMNOPQ"
suffix = "ack"
for letter in prefixes:
print(letter + suffix, end=" ")
Výstup programu je tento:
>>> Jack Kack Lack Mack Nack Oack Pack Qack
V pořádku to úplně není, protože Ouack a Quack nejsou zapsáni správně. Tuto chybu
napravíme v rámci cvičení 6.13.1.
5.4 Podmínka while
Opakovaný výpočet pro jednotlivé elementy iteráblu lze s výhodou provést pomocí smyčky while:
Použití podmínky while si ukážeme na funkci countdown:
def countdown(n): # parametr n jako počáteční stav počítadla
while n > 0: # omezující podmínka
print(n, end=" ")
n = n-1 # změna stavu počítadla
Příkaz while se dá číst téměř jako prostý text: Pokud bude n > 0, vytiskni hodnotu n a
potom ji zmenši o 1. Když se dostaneš k hodnotě n = 0, hodnocení podmínky končí.
Formálněji popíšeme tok výpočtu s příkazem while takto:
- Vyhodnoť podmínku while s výstupem False nebo True.
- Je-li hodnocení False, vystup ze smyčky while a pokračuj dalším příkazem (pokud existuje).
- Je-li hodnocení True, proveď všechny příkazy v těle podmínky a vrať se ke kroku 1.
Tělo podmínky tvoří všechny příkazy pod záhlavím podmínky se stejným odsazením.
Tento typ toku programu se nazývá smyčka, protože se opakovaně vracíme k počátku.
Uvědomme si, že když je podmínka nepravdivá již při prvním běhu smyčkou, příkazy uvnitř smyčky se
nikdy neprovedou.
Tělo smyčky by mělo měnit hodnotu jedné či více proměnných tak, aby se podmínka nakonec stala nepravdivou
a smyčka skončila. Jinak by se opakovala do nekonečna, a byla by to nekonečná smyčka.
V případě funkce countdown(n) můžeme dokázat, že smyčka končí, protože víme, že hodnota n je
konečná a že se při každém průchodu smyčkou zmenšuje, takže nakonec se musíme dostat k nule. V jiných
případech to tak zřejmé být nemusí.
def sequence(n):
while n != 1:
print(n, end=", ")
if n%2 == 0: # n je sudé
n = n//2
else:
n = n*3+1
>>> sequence(4)
4, 2,
>>> sequence(3)
3, 10, 5, 16, 8, 4, 2,
Podmínkou pro tuto smyčku je n != 1, takže bude rotovat tak dlouho, dokud nebude n=1,
čímž se stane podmínka nepravdivá.
Při každém průchodu smyčkou program vrácí hodnotu n a zkontroluje, je-li sudá
či lichá. Je-li sudá, je n děleno 2. Je-li lichá, nahradí se hodnotou n*3+1 - viz "sequence(3)".
Protože se n někdy zvětšuje, jindy zmenšuje, nemáme zřejmý důkaz, že n někdy
dospěje k 1, nebo že program skončí. Pro jisté hodnoty n můžeme ukončení dokázat. Například,
bude-li počáteční hodnotou mocnina 2, bude n stále sudé, dokud nedospěje k 1. V předchozím případě výsledná
posloupnost takovou řadu (počínající číslem 16) obsahuje.
Odhlédneme-li od zmíněných čísel, je na místě otázka, zda umíme dokázat, že tento program je
konečný pro všechny možné hodnoty n. Zatím se to nikomu nepodařilo!
Jiným příkladem použití smyčky while je traverzování po elementech seznamu:
trampol.py # Výběr slov se sudým pořadím
slova = ["Copak", "je", "to", "za", "fešáka", "?"]
i = 0
délka = len(slova)
while i < délka :
if i % 2 == 1 : # podmínka 'if' v podmínce 'while'
print(slova[i], end=", ")
i += 1
>>> %Run trampol.py
je, za, ?,
Následující ukázka demonstruje použití pojmenovaného přiřazení (walruss operator) v kombinaci s podmínkou while a vstupem uživatele:
while (user_input := input('Enter q or p: ')) != 'q':
if user_input == 'p':
print("Hello!")
else: print("Quit!") # jeden blok kódu
>>> Enter q or p: p
Hello!
>>> Enter q or p: q
Quit!
>>>
5.5 Podmínky if.. elif.. else
K napsání užitečného programu potřebujeme mít možnost měnit chování programu v závislosti na splnění či nesplnění jistých podmínek.
Tyto podmínky se formulují pomocí relačních (kap. 2.6.5) a logických (kap. 2.6.6) operátorů.
5.5.1 Podmínka if..
Tuto jednoduchou podmínku je vhodné použít jako součást jiné procedury, například funkce:
def odmocnina(x):
if x >= 0:
print ("odmocnina", x, "=", x**0.5)
Stejně jako funkce a jiné složené příkazy se podmínka if skládá ze záhlaví a těla. Záhlaví začíná klíčovým slovem if, pokračuje booleovským výrazem neboli podmínkou a končí dvojtečkou.
Poté, co se podmínka vyhodnotí jako pravdivá, provede se odsazená část složeného příkazu.
>>> odmocnina(5)
odmocnina 5 = 2.23606797749979
Varianta s úpravou desetinného čísla pomocí f-stringu (viz 6.8.3):
def odmocnina(x):
if x >= 0:
y = x**0.5
print (f"odmocnina {x} = {y:.2f}")
>>> odmocnina(5)
odmocnina 5 = 2.24
5.5.2 Podmínka if .. else
Touto podmínkou realizujeme takzvané alternativní provedení, při němž existují dvě možnosti a podmínka
určí, která z nich se provede:
x = int(input("Zadej celé číslo: ")) # ošetření vstupu z konzoly
if x % 2 == 0: # při splnění podmínky
print (x, "je sudé") # se provede odsazený příkaz
else: # při nesplnění podmínky
print (x, "je liché") # se provede tento příkaz
>>> Zadej celé číslo: 15
15 je liché
Je-li zbytek po dělení dvěma roven nule, potom víme, že x je sudé a program tuto zprávu zobrazí.
Není-li tato podmínka pravdivá, provede se druhá sada příkazů. Protože podmínka může být pouze pravdivá
nebo nepravdivá, provede se určitě jedna z obou možností.
Alternativám říkáme větve protože jsou
rozvětvením toku programu.
Mimochodem, kdybychom potřebovali často posuzovat "lichost" či "sudost" čísel, mohli bychom si tento
prográmek "zabalit" do funkce:
def parita(x):
if x%2 == 0: # % je operátor modulo
print(x, "je sudé")
else:
print(x, "je liché")
Podmínku if .. else lze také uplatnit jako infix mezi dvěma výstupy:
def parita(x):
print(x, " je sudé") if x%2 == 0 else print(x, " je liché")
Pro každou hodnotu x vrátí parita příslušnou zprávu. Při volání můžeme zadat
jako argument jakýkoliv celočíselný výraz:
>>> parita(41)
41 je liché
>>> y = 41; parita(y + 1)
42 je sudé
5.5.3 Podmínka if .. elif .. else
Někdy jsou více než dvě možnosti a my potřebujeme více než dvě větve. Použijeme seriově uspořádané (zřetězené) podmínky:
def compare(x,y):
if x < y:
print(x, "is less than", y)
elif x > y:
print(x, "is greater than", y)
else:
print(x, " and ", y, " are equal")
elif je zkratka "else if". Opět je provedena pouze jedna větev. Počet elif není
omezen, příkaz else však smí být pouze jeden a musí být uveden jako poslední.
Podmínky jsou zkoumány jedna za druhou. Je-li první nepravdivá, prověřuje se další. Je-li některá
pravdivá, provede se bezprostředně následující větev programu. Jestliže je pravdivých podmínek více,
provede se jen první z nich.
5.5.4 Procedura 'match a case'
Procedura match a case imituje v Pythonu neexistující proceduru switch-case. Tato procedura nahrazuje sekvenci podmínek if.., elif.., elif.., else, popsanou v předchozím odstavci.
Sekvence if, elif, else může být někdy i nepřesná:
def věk_skupiny(age):
if age <= 0:
print("Neplatný údaj")
if age < 18:
print("Mladistvý")
elif age < 65:
print("Dospělý")
else:
print("Senior")
'''
věk_skupiny(0) # Podařilo se nám zadat věk, který vyhovuje dvěma skupinám
Neplatný údaj
Mladistvý
'''
Proceduru switch-case si ukážeme na
konkretním příkladě:
def věk_skupiny(age):
match age:
case _ if age < 0:
print("Neplatný údaj")
case _ if age <= 13:
print("Dítě")
case _ if age < 18:
print("Mladistvý")
case _ if age < 65:
print("Dospělý")
case _:
print("Senior")
Poznámka: Podtržítka lze nahradit argumentem 'age'.
>>> print(věk_skupiny(25))
Dospělý
5.5.5 Vnořené podmínky
Jedna podmínka může být vnořena do druhé. Předchozí zřetězené podmínky v odstavci 5.5.3 můžeme realizovat také takto:
def compare_imb(x,y):
if x == y:
print(x, "and", y, "are equal")
else:
if x < y:
print(x, "is less than", y)
else:
print(x, "is greater than", y)
>>> compare_imb(9,12)
9 is less than 12
Zřetězenou podmínku else jsme doplnili vnořenou dvojicí zřetězených podmínek if a else.
I když odsazení příkazů činí strukturu zápisu zřejmou, vnořené podmínky se velmi rychle stávají méně přehledné. Pokud můžeme, tak se jim raději vyhneme.
Podmínky lze často vyjádřit logickými operátory. Následující kód bude v další ukázce přepsán pro
použití jen jedné podmínky:
def podm1(x):
if 0 < x:
if x < 10: # vnořená podmínka
print("číslo x je tvořeno kladnou číslicí.")
K volání funkce print dojde také tehdy, splníme-li obě podmínky zadané jedním výrazem (0 < x < 10).
def podm2(x):
if 0 < x < 10:
print("číslo x je tvořeno kladnou číslicí.")
5.5.6 Příkaz break
Při splnění podmínky ukončí příkaz break provádění smyčky. Tento příkaz lze použít u smyček for i while:
def finito(x):
for letter in "Python":
if letter == x:
break
print("Current Letter: ", letter)
finito('h')
Current Letter: P
Current Letter: y
Current Letter: t
nebo:
var = 8
while var > 0:
print("Current var. value: ", var)
var = var - 1 # lze nahradit příkazem var -= 1
if var == 5:
print("Adieu, var ==", var)
break # ukončí provádění smyčky
Current var. value: 8
Current var. value: 7
Current var. value: 6
Adieu, var == 5
5.5.7 Přikaz continue
Při splnění podmínky přeruší příkaz continue provádění smyčky a její výpočet pokračuje dalším elementem sekvence. Tento příkaz lze použít u smyček for i while:
def contin(x):
for letter in "Python":
if letter == "h":
print(" Jsme přerušeni!")
continue
print("Current Letter: ", letter)
contin("h")
Current Letter: P
Current Letter: y
Current Letter: t
Jsme přerušeni!
Current Letter: o
Current Letter: n
nebo:
var = 6
while var > 0:
var = var - 1
if var == 3:
print(" Jsme přerušeni!")
continue
print("Current var. value: ", var)
print("Adieu!")
Current var. value: 5
Current var. value: 4
Jsme přerušeni!
Current var. value: 2
Current var. value: 1
Current var. value: 0
Adieu!
5.6 Funkce len()
Touto často používanou vestavěnou funkcí zjistíme počet prvků iterovatelného objektu ze skupiny sekvence (string, list, tuple, range, bytes, bytearray, memoryview) a kolekce (set, frozenset, dict) - příkladmo:
>>> sg = "halelujah" # typ string
>>> len(sg)
9
>>> bts = b'R\xc5\xaf\xc5\xbee' # typ bytes
>>> len(bts)
6
5.7 Funkce range
Vestavěná funkce
range(n) # jen koncová mez
range(m, n) # (start, stop)
range(m, n, p) # (start, stop, krok)
vytvoří potenciální číselnou posloupnost od 0 po n-1, případně od m po n-1, případně od m po n-1 s krokem p. Argumenty m a p jsou nepovinné.
Slovo potenciální označuje tu skutečnost, že místo celé zadané řady (celých) čísel se při deklaraci uloží pouze její parametry a k vlastnímu vytvoření této posloupnosti dojde až při jejím volání. Jedná se o případ takzvaného líného (lazy) vytvoření iterovatelného objektu.
Předností funkce range() je skutečnost, že zabírá stejné místo v paměti - bez ohledu na délku deklarované řady čísel.
Tuto posloupnost lze použít jako argument při tvorbě prostého seznamu, entice, setu a sekvence bytes:
>>> list(range (7)) # chápáno jako range(0,7)
[0, 1, 2, 3, 4, 5, 6]
>>> tuple(range (2,7)) # tuple je naše entice
(2, 3, 4, 5, 6)
>>> set(range (0,7,2))
{0, 2, 4, 6}
>>> bytes(range (0,7,2))
b'\x00\x02\x04\x06'
>>> list(range (7,5)) # bez vhodného kroku vždy prázdný
[]
>>> list(range (7,0,-3)) # vida
[7, 4, 1]
Obrácenou posloupnost lze vytvořit i bez obrácených mezí a záporného kroku pomocí funkce reversed(). Tento postup nechodí pro objekt typu set a frozenset.
>>> list(reversed(range(7)))
[6, 5, 4, 3, 2, 1, 0]
>>> list(reversed(range(0,7,2)))
[6, 4, 2, 0]
Objekt typu range je indexovatelným (subscriptable) objektem. Jeho elementy jsou individuálně přístupné uvedením indexu v hranaté závorce i metodou __getitem__():
>>> range(7)[2]
2
>>> range(7).__getitem__(2)
2
Iterátor lze z objektu range vytvořit běžným způsobem funkcí iter(range), range.__iter__() nebo smyčkou for..., která si iterátor vytvoří sama (sama si jej však také zkonzumuje). Iterace takovéhoto iterátoru je dychtivá (eager).
>>> for i in range(7): # eager iteration
print(i, end= ", ")
0, 1, 2, 3, 4, 5, 6,
>>> for number in range(20): # eager iteration
if number%3 == 0:
print(number, end=" ")
0 3 6 9 12 15 18
5.8 Funkce enumerate
Volání funkce enumerate(iterable, start=0) vrací objekt typu enumerate jenž je iterátorem, disponujícím metodou __next__() a funkcí next(). Parametr start je nepovinný, 0 je jeho implicitní hodnotou.
>>> fruits = ('banana','apple','pear','grape') # iterábl
>>> enum = enumerate (fruits) # iterátor
>>> type(enum) # --> <class 'enumerate'>
Objekt typu enumerate není indexovatelný (není to iterábl), jeho elementy nejsou přímo přístupné prostřednictvím indexu v hranatých závorkách.
>>> enum[1]
# TypeError: 'enumerate' object is not subscriptable
Přístup k prvkům iterátoru lze realizovat postupně prostřednictvím iterační funkce next nebo smyčky for::
>>> next(enum)
(0, 'banana')
>>> enum.__next__()
(1, 'apple')
>>> for index in enum:
print(index, end=" ")
(2, 'pear') (3, 'grape') # zbytek iterace
Jak vidno, next(enum) i smyčka for vrací index a jemu příslušnou hodnotu. Index implicitně počíná nulou. Počáteční index lze změnit zadáním jiné hodnoty pro parametr start.
Funkci enumerate lze použít pro vyjádření vztahu argument - upravený argument:
>>> numbers = [2, 3, 4, 5]
>>> for index, value in enumerate (numbers):
print(numbers[index], " -> ", value**2)
2 -> 4
3 -> 9
4 -> 16
5 -> 25
5.9 Funkce filter, map a zip
Všechny tyto tři funkce (vyššího řádu) pracují s iterovatelnými objekty (iterábly - viz 3.1) a produkují iterátory.
Funkce filter(function, iterable) extrahuje ty prvky ze zadaného iteráblu (list, string, tuple, set, ...), pro něž zadaná funkce s podmínkou (predicate) vrací hodnotu True. Jako funkce s predikátem se často používá anonymní funkce lambda.
Funkce filter() vrací iterátor, jenž musíme vhodným způsobem rozbalit, například funkcí list(), tuple(), set():
>>> ages = [7, 10, 16, 18, 26, 35] # iterábl
>>> adults = filter(lambda x: x > 17, ages)) # iterátor
>>> print("Adults: ", list(adults)) # nutno rozbalit
Adults: [18, 26, 35]
# Případně iterátor rozbalíme hned:
>>> not_adults = tuple(filter(lambda x: x >= 17, ages))
>>> print("Not adults: ", not_adults)
Not adults: (7, 10, 16)
Iterátor lze rozbalit i smyčkou for ... :
>>> for i in filter(lambda x: x % 2 = 17, ages):
print(i, end=" ")
10 16 18 26
Pro přetvoření iteráblu lze použít i formát predikátové funkce:
>>> ages = [7, 10, 16, 18, 26, 35]
>>> def is_even(x): # predikátová funkce
return x % 2 == 0 # vrací True nebo False
>>> print(set(filter(is_even, ages)), end='')
{10, 16, 18, 26}
Argumentem pro parametr x je zde element seznamu ages.
Funkce map() aplikuje zadanou transformační funkci na každý element zadaného iteráblu (seznamu, entice, atp) a vrací sekvenci výsledků jako objekt map, což je iterátor, který nutno rozbalit (zde funkcí list).
>>> numbers = 1, 2, 3, 4 # iterábl
>>> def squares(n): # transformační funkce
return n*n
>>> result = list(map((squares, numbers))
>>> result
[1, 4, 9, 16] # objekt již rozbalený
Jiný příklad s funkcí lambda:
>>> num1 = [4, 5, 6] # Iteráblů lze zadat více než jeden.
>>> num2 = [5, 6, 7]
# Zřetězení funkcí list() a map():
>>> result = list(map(lambda x,y: x+y, num1, num2)); result # iterátor
[9, 11, 13]
Rozbalení stringů do entic použitím funkce list() a tuple():
>>> tup = 'šach', 'mat', 'pat' # iterábl
>>> test = list(map(tuple, tup)) # rozbalený iterátor
>>> print(test)
[('š', 'a', 'c', 'h'), ('m', 'a', 't'), ('p', 'a', 't')]
Funkce map() je napsaná v jazyce C. Obsahuje interní smyčku for ... s menším nárokem na potřebu paměti než tatáž smyčka, psaná v Pythonu.
Funkce zip(iterables) přijímá dvě či více iterovatelných sekvencí (iteráblů) a vytváří objekt typu zip, v němž jsou zadané sekvence agregované do jediné sekvence entic iterátoru.
>>> izip = zip([1, 2, 3], "postel", range(6)); izip
<zip object at 0x000001E753183380> # iterátor
>>> list(izip)
[(1, 'p', 0), (2, 'o', 1), (3, 's', 2)] # seznam
# Iterátor je prázdný, nutno jej znovu deklarovat:
>>> izip = zip([1, 2, 3], "postel", range(1,5))
>>> set(izip)
{(3, 's', 2), (2, 'o', 1), (1, 'p', 0)} # set
# nebo sloučit deklaraci sekvence s deklarací iterátoru:
>>> tuple(zip([1, 2, 3], "postel", range(6)))
((1, 'p', 0), (2, 'o', 1), (3, 's', 2)) # entice
>>> dict(zip([1, 2, 3, 4], "postel"))
{1: 'p', 2: 'o', 3: 's', 4: 't'} # slovník
Počet entic ve výsledné sekvenci je dán počtem argumentů funkce zip. Délka výsledných entic je dána délkou nejkratšího argumentu. U slovníku mohou být pouze dva argumenty. Jeho enticemi jsou dvojice klíč:hodnota.
Od verze Python 3.10 existuje pojmenovaný argument strict=True, který zkontroluje délku vstupních argumentů a v případě neshody hlásí chybu:
>>> set(zip([1, 2, 3, 4], "postel", strict=True))
ValueError: zip() argument 2 is longer than argument 1
Je nicméně možné vytvořit iterátor podle nejdelší vstupní sekvence a to pomocí funkce zip_longest() z modulu itertools:
>>> from itertools import zip_longest
>>> numb = [1, 2, 3]
>>> lett = ['a', 'b', 'c']
>>> long = range(5)
>>> izip = zip_longest(numb, lett, long, fillvalue='#')
>>> list(izip)
[(1, 'a', 0), (2, 'b', 1), (3, 'c', 2), ('#', '#', 3), ('#', '#', 4)]
Souhrnná poznámka
Výstupem z funkce filter(), map(), zip() je iterátor a lze jím procházet (traverzovat) funkcí iter() nebo smyčkou for ... :
>>> izip = zip([1, 2, 3], "postel", range(6))
>>> next(izip)
(1, 'p', 0)
>>> for i in izip:
print(i)
(2, 'o', 1)
(3, 's', 2)
>>> next(izip) # iterátor je prázdný
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
# Prázdný iterátor zaplníme opětovným voláním proměnné izip.
Interní objekt iterátoru lze také rozbalit funkcí list(), tuple(), set() a dict.
5.10 Funkce reduce
Funkce vyššího řádu reduce(fce, iterable, initial) vrací jedinou výslednou hodnotu z postupné aplikace zadané funkce pro dvě po sobě zadané hodnoty v sekvenci. Parametr initial je nepovinný. Tuto funkci nutno importovat z modulu functools.
>>> from functools import reduce
>>> seqv = 1,2,3,4
# S funkcí pro dva argumenty:
>>> def do_sum(x, y):
return x + y
>>> reduce(do_sum, seqv) --> 10
Případně s funkcí lambda:
>>> reduce(lambda x,y: x+y , range(1,5)) --> 10
Případně s hodnotou pro nepovinný parametr initial:
>>> reduce(do_sum, seqv, 12) --> 22
Funkce reduce() zde postupně provádí součty (((1+2)+3)+4), eventuelně (((12 (argument pro parametr initial) +1)+2)+3)+4).
Hodnota parametru 'initial' se při realizaci funkce reduce() zařadí na první pozici zpracovávané sekvence. Datové typy argumentů pro sekvenci i parametr 'initial' musejí být shodné.
Parametr initial je důležitý pro situaci, kdy by argument pro parametr iterable měl být prázdný. V tom případě by funkce reduce() bez argumentu pro initial skončíla sdělením TypeError.
Inteligentní náhradou invokace reduce(do_sum, seqv) je funkce sum(num_seqv), kde num_seqv je řada čísel - s tím rozdílem, že sum() neumí slučovat řetězce jako funkce reduce():
>>> sum(seqv)
10
Pro sumaci řetězců (konkatenaci) lze použít tento výraz:
>>> from functools import reduce
>>> faq = "pes", "kočka"
>>> reduce(lambda x,y: x+y, faq, "sumace = ")
'sumace = peskočka'
5.11 Newtonova metoda
Smyčky jsou často užívány v programech, které spočítají výsledek tak, že začnou s přibližnou hodnotou a opakovaným výpočtem výsledek zpřesňují.
Například, jedním ze způsobů počítání druhé odmocniny čísla je Newtonova metoda. Při určení odmocniny čísla n začneme v podstatě libovolnou aproximací (přibližnou hodnotou), kterou zpřesníme pomocí tohoto vzorce:
better = (approx + n/approx) / 2
Výpočet se opakuje tak dlouho, až se zpřesněná hodnota téměř neliší od předchozí. Pro provádění výpočtu napíšeme funkci:
def sqrt(n):
approx = n/2.0
better = (approx + n/approx)/2.0
while better != approx:
approx = better
better = (approx + n/approx)/2.0
return approx
Volejme funkci pro argument 25 , abychom se přesvědčili, že výsledek je 5 .
Newtonova metoda je příkladem algoritmu - obecného řešení určitého problému (v našem případě počítání druhé odmocniny).
5.12 Cvičení
Napište definice funkcí s invokacemi v zadaných doctestech. Všechny příklady zapisujte do samostatných souborů ve složce Kap-05.
Příklady s doctestem budou mít na konci skriptu tento kód:
if __name__ == '__main__':
import doctest
doctest.testmod()
Tyto příklady řešte až po prostudování textu v kap. 3.10.
- Napište funkci compare(a,b), která vrací 1 pro a>b, 0 pro a==b a -1
pro a<b.
def compare (a, b):
"""
>>> compare(5,4)
1
>>> compare(7,7)
0
>>> compare(2,3)
-1
"""
# Zde napište tělo funkce
- Napište funkci hypo, která vrací délku přepony pravoúhlého trojúhelníka pro zadané délky odvěsen.
def hypo (a,b):
"""
>>> hypo(3,4)
5.0
>>> hypo(12,5)
13.0
>>> hypo(7,24)
25.0
"""
# tělo funkce může mít pouhé 2 řádky
- Napište funkci slope(x1,y1,x2,y2), která vrací tangent úhlu (sklonu) přímky procházející body
(x1,y1) a (x2,y2). Funkce musí vyhovět následujícím testům:
def slope (x1,y1,x2,y2):
"""
>>> slope(5,3,4,2)
1.0
>>> slope(1,2,3,2)
0.0
>>> slope(1,4,1,2)
kolmice k ose 'x' Ošetřená výjimka!
>>> slope(2,4,1,2)
2.0
"""
# Zde napište tělo funkce
-
Napište funkci intercept(x1,y1,x2,y2), která vrací ypsilonovou pořadnici průsečíku přímky s osou y (pro x=0). Použijte rovnici přímky, procházející 2 body.
def intercept (x1,y1,x2,y2):
"""
>>> intercept(1,6,3,12)
3.0
>>> intercept(6,1,1,6)
7.0
>>> intercept(4,6,12,8)
5.0
"""
# Zde napište tělo funkce
- Napište funkci is_multiple(m,n), která vrátí True,
je-li m násobkem n a False, není-li.
def is_multiple( (m,n):
"""
>>> is_multiple(12,3)
True
>>> is_multiple(12,4)
True
>>> is_multiple(12,5)
False
"""
# Zde napište tělo funkce
Napište fci is_divisible(m,n), která přijme celá čísla jako argument a podle situace vytiskne True nebo False.
def is_divisible( (m,n):
"""
>>> is_divisible(20,4)
True
>>> is_divisible(21,8)
False
"""
# Zde napište tělo funkce
Při řešení použijete podmínky if ... :, else: a vyberete si jeden z existujících způsobů dělení: normální a/b, celočíselné a//b nebo dělení se zbytkem (modulo) a%b.
- Napište tělo funkce fah2cel(t), která převede teplotu ve stupních Fahrenheitových na stupně Celsiovy a vrátí ji jako celé číslo. Použijete vestavěnou fci round(n). Informaci o této funkci získáte zadáním round.__doc__ v konzole Pythonu.
def fah2cel(t):
"""
>>> fah2cel(212)
100
>>> fah2cel(32)
0
>>> fah2cel(-40)
-40
>>> fah2cel(37)
3
"""
# Zde napište tělo funkce
- Napište funkci cels2fah(t), která převede teplotu ve stupních Celsiových na stupně Fahrenheitovy.