Funkce print() se všemi svými parametry má tento tvar:
objekty ,sep ="",end ="\n",file =sys.stdout,flush =False)
Kdo si přečetl odstavec 4.2 Parametry a argumenty, ví že parametr
Takže se nám povinný tvar volání funkce smrskne na:
přičemž i tento parametr lze vynechat a v tom případě nám funkce vytiskne prázdný řádek.
>>> print("\n")# vytiskne 1 prázdný řádek Případně >>> print(3*"\n")# vytiskne 3 prázdné řádky
Funkce
>>> print("Je mi", 12 + 9, "let.") Je mi 21 let.# fce print() odebrala apostrofy >>>
Párové argumenty
Změnou argumentu
Změnou argumentu
>>> 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" zůstal příkaz print()
Ve funkci s větvenými podmínkami s výhodou použijeme příkaz
def filtr (x):if x <= 0:# = P return "Přirozené číslo, prosím"# if P is True return x# if p is False
Protože jsou tyto příkazy v alternativních podmínkách, provedou se pouze jednou - jakmile se jeden z příkazů
Kód, který je zapsán za příkazem
Je dobré aby každá možná cesta funkcí narazila na příkaz
def absolute_value (x):if x < 0:return -xelif x > 0:return x
Tato verze není zcela správná, protože bude-li
>>> print(absolute_value(0)) None
Příkaz
Smyčka
for i in container : do something
st = {3.6, "cat", True}# kolekce typu set for iin st:
True 3.6 cat
Na výstupu idiomu
Iterace
sl = {1: "uno", 2: "duo", 3: "tre"}# kolekce typu dict for iin sl:
1 2 3
Případně:
sl = {1: "uno", 2: "duo", 3: "tre"}# kolekce typu dict for i,jin sl.items():
1 uno 2 duo 3 tre
O tom, že naše kontejnery jsou vybaveny metodou
>>>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
Funkce
>>> f = open("F:/Codetest/Abakus/week.txt")# iterátor pro week.txt >>> next(f)# první řádek souboru 'pondělí\n' >>> next(f)# další řádek souboru úterý >>> for i in f: print(i, end=" ")# zbývající řádky souboru středa ...
Následující příklad ukazuje použití zřetězení (concatenation) a smyčku
prefixes = "JKLMNOPQ" suffix = "ack"for leclr-tterin prefixes:
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.17.1.
Opakovaný výpočet pro jednotlivé elementy iteráblu lze s výhodou provést pomocí smyčky while:
Použití příkazu
def countdown (n):# parametr n jako počáteční stav počítadla while n > 0:# omezující podmínka # změna stavu počítadla
Příkaz
Formálněji popíšeme tok výpočtu s příkazem
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
def sequence (n):while n != 1:if n%2 == 0:# n je sudé n = n//2else : n = n*3+1
>>> sequence(4) 4, 2, >>> sequence(3) 3, 10, 5,16 , 8, 4, 2,
Podmínkou pro tuto smyčku je
Při každém průchodu smyčkou program vrácí hodnotu
Protože se
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
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 :
>>>%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 (user_input := input('Enter q or p: '))!= 'q':if user_input == 'p':else :
>>>Enter q or p: p Hello! >>>Enter q or p: Quit!
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.4) a logických (kap. 2.6.5) operátorů .
Tuto jednoduchou podmínku je vhodné použít jako součást jiné procedury, například funkce:
def odmocnina (x):if x >= 0:
Stejně jako funkce a jiné složené příkazy se příkaz
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í
def odmocnina (x):if x >= 0: y = x**0.5f "odmocnina {x} = {y:.2f}")
>>> odmocnina(5) odmocnina 5 = 2.24
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 # se provede odsazený příkaz else :# při nesplnění podmínky # 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
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 print_parity (x):if x%2 == 0:# % je operátor modulo else :
Podmínku
def print_parity (x):if x%2 == 0else print(x, " je liché")
Pro každou hodnotu
>>> print_parity(41) 41 je liché >>> y = 41 >>> print_parity(y + 1) 42 je sudé
Někdy jsou více než dvě možnosti a my potřebujeme více než dvě větve. Použijeme seriově uspořádané (
if x < y:elif x > y:else :
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.
Sekvencí podmínek
Mějme skript s funkcemi
Výstupem v konzole interpreta by mělo být:def fce_a ():def fce_b ():def fce_c ():def if_case (choice):if choice == 'a': fce_a()elif choice == 'b': fce_b()elif choice == 'c': fce_c()else: print("Neplatná volba")
>>> if_case("c") fce_c byla volána >>> if_case(5) Neplatná volba
Jedna podmínka může být vnořena do druhé. Předchozí trojité větvení můžeme realizovat také takto:
if x == y:else :if x < y:else :
Vnější podmínka má dvě větve. První větev obsahuje prostý příkaz k tisku. Druhá větev obsahuje
další podmínku
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.
Vnořené podmínky můžeme často zjednoduš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:
if 0 < x:if x < 10:
K volání funkce
if 0 < xand x < 10:
Při splnění podmínky ukončí příkaz
for letterin "Python":if letter== "h":break
Current Letter: P Current Letter: y Current Letter: t
nebo:
var = 8while var> 0:if var== 5:break
Current var. value: 8 Current var. value: 7 Current var. value: 6 Adieu!
Při splnění podmínky přeruší příkaz
for letterin "Python":if letter== "h":continue
Current Letter: P Current Letter: y Current Letter: t Jsme přerušeni! Current Letter: o Current Letter: n
nebo:
var = 6while var> 0: var = var - 1if var== 3:continue
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!
Touto často používanou vestavěnou funkcí zjistíme počet prvků iterovatelného objektu ze skupiny
>>> sg = "halelujah"# typ string >>> len(sg) 9 >>> bts = b'R\xc5\xaf\xc5\xbee'# typ bytes >>> len(bts) 6
Vestavěná funkce
range (n )# jen koncová mez range (m, n )range (m, n, p )# (start, stop, krok)
vytvoří
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
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
>>> 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
>>> 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
>>> range(7)[2] 2 >>> range(7).__getitem__(2) 2
Iterátor lze z objektu range vytvořit běžným způsobem funkcí
>>> for i in range(7):# eager iteration print(i, end= ", ") 0, 1, 2, 3, 4, 5, 6,
for numberin range(20):# eager iteration if number%3 == 0:
0 3 6 9 12 15 18
Volání funkce enumerate(iterable, start=0) vrací objekt typu
>>> 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(enum) (0, 'banana') >>> enum.__next__() (1, 'apple') >>> for index in enum: print(index, end=" ") (2, 'pear') (3, 'grape')# zbytek iterace
Jak vidno,
Funkci 'enumerate' lze použít pro vyjádření vztahu argument - upravený argument:
numbers = [2, 3, 4, 5]for index, valuein enumerate (numbers):
2 -> 4 3 -> 9 4 -> 16 5 -> 25
Všechny tyto tři funkce (vyššího řádu) pracují s iterovatelnými objekty (iterábly - viz 3.1) a produkují
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
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 >>>list (adults))# nutno rozbalit Adults: [18, 26, 35]# Případně iterátor rozbalíme hned: >>> not_adults =tuple (filter (lambda x: x <= 17, ages)) >>>
Iterátor lze rozbalit i smyčkou for ... :
>>> for i in filter(lambda x: x % 2 == 0, ages): print(i, end=" ") 10 16 18 26
Pro přetvoření iteráblu lze použít i formát funkce s predikátem:
>>> def is_even(x): return x % 2 == 0# vrací True nebo False >>> print(set(filter(is_even, ages)), end='') {10, 16, 18, 26}
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
numbers = 1, 2, 3, 4# iterábl def squares(n):# transformační funkce return n*n result =map (squares, numbers); result<map object at 0x000001AE79FA3460> # iterátor, list (result)# který nutno rozbalit --> [1, 4, 9, 16]
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 --> [('š', 'a', 'c', 'h'), ('m', 'a', 't'), ('p', 'a', 't')]
Funkce map() je napsaná v jazyce C. Obsahuje interní smyčku
Funkce zip(
>>> 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
Ve verzi
>>> 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
>>> 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)]
Výstupem z funkce
>>> 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)Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration # iterátor je prázdný Prázdný iterátor zaplníme opětovným voláním proměnné .izip
Interní objekt iterátoru lze také rozbalit funkcí
Funkce vyššího řádu reduce(
from functools import reduce seqv = 1,2,3,4def do_sum (x, y):# funkce pro dva argumenty return x + yreduce (do_sum, seqv)--> 10 Případně s hodnotou pro parametr initial :reduce (do_sum, seqv, 12)--> 22 Případně s funkcí lambda: reduce (lambda x,y: x+y , range(1,5))--> 10
Funkce reduce() zde postupně provádí součty (((1+2)+3)+4), eventuelně (((12 (argument pro parametr
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
Inteligentní náhradou invokace
>>> sum(seqv) 10Pro 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'
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
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.0while better != approx: approx = better better = (approx + n/approx)/2.0return approx
Volejme funkci pro argument
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).
Napište definice funkcí s invokacemi v zadaných doctestech. Všechny příklady zapisujte do samostatných souborů ve složce
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.
def compare (a, b): """ >>> compare(5,4) 1 >>> compare(7,7) 0 >>> compare(2,3) -1 """# Zde napište tělo funkce
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
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
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
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
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.
def fah2cel (t): """ >>> fah2cel(212) 100 >>> fah2cel(32) 0 >>> fah2cel(-40) -40 >>> fah2cel(37) 3 """# Zde napište tělo funkce