Pravidlá pre formátovanie¶
Ak nebudete dodržiavať odsadzovanie, interpreter vypíše chybu a program nebude spustený. Aby ste zlepšili čitateľnosť vášho kódu, je dobré dodržiavať nasledujúce konvencie:
- Rozhodnite sa ako budete ohraničovať reťazce a dodržiavajte jeden spôsob v celom kóde (ohraničenia môžete vymeniť ak reťazec obsahuje
'
alebo"
aby ste nemuseli používať\'
alebo\"
). - Premenné a funkcie označujte názvami s malými písmenami. Viacslovné názvy oddeľujte
_
(napr.process_data
). - Premenné, ktoré budú slúžiť v programe ako konštanty a ktoré sa nebudú pri spustení meniť pomenujte veľkými písmenami oddelenými
_
(napr.DEFAULT_VALUE
). - Vždy oddeľte operátory
=
,+=
,-=
,==
,!=
,<
,>
,<=
,>=
, is, in a Boolovské spojkyor
,and
anot
medzerami (napr.x < 10
namiestox<10
). - Vyhnite sa vkladaniu medzier hneď za/pred
[/]
,(/)
, alebo{/}
(napr.x[10]
namiestox[ 10 ]
,f(x)
namiestof( x )
,{'x': 'y'}
namiesto{ 'x' : 'y' }
).
Ďalšie odporúčania nájdete tu (v angličtine).
Funkcie¶
Funkcie v Pythone definujete pomocou kľúčového slova def
za ktorým nasleduje meno funkcie a zoznam parametrov v zátvorkách ()
oddelených čiarkou. Príkazy funkcie musia byť odsadené od začiatku riadku.
Nasledujúci kód definuje funkciu print_value
s jedným parametrom označeným value
. Funkcia vypíše hodnotu value
ak nie je prázdna, inak neurobí nič.
def print_value(value):
if value is None:
return # pre prázdnu hodnotu príkaz ‘return’ ukončí funkciu a nasledujúci print sa už nevykoná
print(value)
# zavoláme definovanú funkciu a predáme jej parameter value = 123
print_value(123)
Funkcia print_value
nevracia žiadnu hodnotu (jej návratová hodnota je vždy None
). Ak chcete aby funkcia vrátila nejakú hodnotu, použite príkaz return [hodnota]
, napr.:
def sum_squares(data):
"""Computes sum of squares of values for the specified sequence."""
if len(data) == 0: # pre prázdny zoznam vrátime None
return None # ‘return’ ukončí funkciu a ako návratovú hodnotu vráti hodnotu výrazu za slovom ‘return’
sumsq = 0
for x in data:
sumsq += x * x
return sumsq # na konci vrátime sumu štvorcov prvkov zoznamu
# zavoláme funkciu s parametrom data = [1, 2, 3] a jej návratovú hodnotu priradíme premennej x
x = sum_squares([1, 2, 3]) # x = 14
x
Na prvom riadku funkcie sum_squares
je tzv. dokumentačný reťazec (v angličtine docstring), ktorý sa v Pythone používa na dokumentovanie kódu. Dokumentačné reťazce sú uvedené na prvom riadku definovanej funkcie pred ostatnými príkazmi, môžu mať viacero riadkov a sú ohraničené trojitými úvodzovkami """
. Pre funkcie je text reťazca odsadený od začiatku riadka rovnako ako príkazy funkcie. Túto konvenciu potom využívajú rôzne nástroje, ktoré napr. automaticky vyextrahujú HTML dokumentáciu pre všetky funkcie programu.
Interpreter Pythonu má zabudovanú funkciu help
, ktorá pre zadaný názov funkcie alebo modulu vypíše dokumentačný reťazec. Napr. po definovaní funkcie sum_squares
z predchádzajúceho príkladu môžete vypísať jej dokumentáciu nasledujúcim príkazom:
help(sum_squares)
Ďalšie odporúčania pre písanie dokumentačných reťazcov nájdete tu (v angličtine).
Pre parametre funkcie môžete definovať prednastavené hodnoty a parameter potom môžete pri volaní vynechať napr. nasledujúca funkcia definuje prednastavenú hodnotu pre parametre opr
a none_value
. Všetky parametre s prednastavenými hodnotami musia byť uvedené až za nenastavenými parametrami.
def print_operation(x, y, opr="+", none_value="?"):
val_x = none_value if x is None else str(x) # do val_x sa priradí none_value ak je x None, inak sa priradí str(x)
val_y = none_value if y is None else str(y) # podobne pre y
print(val_x + " " + opr + " " + val_y)
Funkciu print_operation
možno volať nasledujúcimi spôsobmi:
print_operation(1, None, "*", "[none]") # vypíše ‘1 * [none]’
print_operation(1, None, "*") # vypíše ‘1 * ?’ - vynechali sme none_value
print_operation(1, None) # vypíše ‘1 + ?’ - vynechali sme opr a none_value
print_operation(x=1, opr="+", y=2) # nemusíte dodržiavať poradie parametrov a nepovinné parametre môžete vynechať
# spôsoby môžete kombinovať, pričom najprv sú uvedené parametre podľa poradia a potom podľa mena
print_operation(1, 2, none_value="[none]")
Všimnite si výnimku z odporúčaní pre formátovanie, pre prednastavené hodnoty parametrov sa neodporúča oddeliť názov parametra a hodnotu od =
medzerou.
Okrem uvedenia parametrov v poradí môžete pri volaní funkcie nastaviť parametre podľa ich mena, napr.:
print_operation(x=1, opr="+", y=2) # nemusíte dodržiavať poradie parametrov a nepovinné parametre môžete vynechať
# spôsoby môžete kombinovať, pričom najprv sú uvedené parametre podľa poradia a potom podľa mena
print_operation(1, 2, none_value="[none]")
Funkciu môžete definovať aj s premenlivým počtom parametrov, napr.:
def print_list(name, *args): # všetky parametre za prvým budú funkcii predané ako n-tica args
print(name + ": [" + ", ".join(args) + "]") # prvky args spojíme oddeľovačom ‘, ’
# funkciu potom možno volať s ľubovoľným počtom parametrov uvedeným za name, napr.
print_list("basket") # vypíše ‘basket: []’
print_list("basket", "apple", "orange") # vypíše ‘basket: [apple, orange]’
Funkcionálne programovanie - Lambda výrazy¶
Funkcie sú v Pythone objekty s ktorými môžete pracovať ako s ľubovoľnou hodnotou, tzn. môžete ich napr. priradiť premennej, predať ich ako parameter pri volaní ďalšej funkcie, alebo môžete mať funkciu ktorá vracia funkciu ako návratovú hodnotu. Funkcionálne programovanie je zvlášť vhodné pre spracovanie veľkých dát, pretože zjednodušuje paralelné a distribuované výpočty.
Nasledujúca funkcia filter skopíruje do nového zoznamu všetky prvky zo zoznamu items
, ktoré spĺňajú podmienku testovanú funkciou f
. Funkcia filter
očakáva, že parameter f
odkazuje na funkciu s jedným parametrom, ktorá vracia Boolovskú hodnotu.
def filter(items, f):
filtered = []
for x in items:
if f(x): # pre každý prvok x zoznamu items zavoláme funkciu na ktorú sa odkazuje parameter f
filtered.append(x) # ak f vráti True, pridáme x do výsledného zoznamu
return filtered # vrátime zoznam hodnôt, ktoré splnili testovanie funkciou f
Definujeme si jednoduchú funkciu s jedným parametrom, ktorá testuje či je hodnota parametra nenulová.
def non_zero(x):
return x != 0 # vráti sa True ak x != 0, inak False
# funkciu non_zero potom môžeme predať ako parameter f funkcii filter
a = [-1, 0, 1, 2, -3]
b = filter(a, non_zero) # = [-1, 1, 2, -3]
b
Jednoduché funkcie s príkazom ‘return’ môžete zapísať priamo ako hodnotu pomocou tzv. lambda výrazu. Lambda výraz má tvar: lambda
zoznam parametrov : návratová hodnota, napr. nasledujúci lambda výraz definuje rovnakú funkciu ako non_zero(x)
:
test = lambda x: x != 0
# test je premenná do ktorej sa uloží funkcia definovaná lambda výrazom
# volanie funkcie priradenej do premennej test je rovnaké ako keby sme definovali funkciu s menom test
test(10) # = True
b = filter(a, test) # = [-1, 1, 2, -3]
# skrátený zápis lambda výrazu je vhodný napr. ak chcete definovať funkciu priamo na mieste, kde sa predá ako parameter:
b = filter(a, lambda x: x != 0)
b
Lambda výraz môžete použiť aj v prípade, že chcete naprogramovať funkciu, ktorá vracia ako návratovú hodnotu funkciu Napr. nasledujúca funkcia test_interval(min, max)
vráti funkciu, ktorá vráti True
ak hodnota jej parametra x
patrí do
intervalu (min
, max
):
def test_interval(min, max):
return lambda x: min < x and x < max # ‘return’ vracia funkciu definovanú lambda výrazom
# vždy keď zavoláme funkciu test_interval(min, max) s rôznymi parametrami min, max vytvorí sa nová testovacia funkcia ktorú
# môžeme samostatne použiť, napr.:
test_interval(0, 10)(5) # = True - vytvorili sme novú testovaciu funkciu, ktorú sme rovno zavolali s parametrom 5
b = filter(a, test_interval(0, 3)) # = [1, 2]
b = filter(a, test_interval(-2, 2)) # = [-1, 0, 1]
Funkcie definované pomocou lambda výrazu sa označujú aj ako anonymné. Okrem funkcie filter
patria medzi ďalšie užitočné funkcie aj map
a reduce
.
# map vráti zoznam, ktorého hodnoty sú vypočítané aplikovaním funkcie f na jednotlivé prvky zoznamu items
def map(items, f):
mapped = []
for x in items:
mapped.append(f(x)) # do výsledného zoznamu pridáme transformovanú hodnotu
return mapped
# vráti zoznam čísiel umocnených na 2
b = map(a, lambda x: x * x) # = [1, 0, 1, 4, 9]
b
Funkcia reduce
očakáva ako parameter opr
funkciu s dvoma parametrami, ktorú postupne aplikuje na prvky zoznamu a výsledok
predchádzajúceho volania opr
, napr. pre zoznam [1,2,3]
funkcia reduce
vypočíta hodnotu:
opr(opr(opr(init, 1), 2), 3)
čo možno zapísať v infixnom tvare ako ((init opr 1) opr 2) opr 3)
.
Hodnota init
(s prednastavenou hodnotou None
) sa používa pri volaní opr
s prvým prvkom zoznamu a je aj návratovou hodnotou
reduce
pre prázdny zoznam.
def reduce(items, opr, init=None):
result = init
for x in items:
result = opr(result, x)
return result
Funkcia reduce
je zvlášť významná pri paralelnom programovaní, kedy sa požaduje aby bola funkcia opr
asociatívna, tzn. aby pre
všetky hodnoty a
, b
, c
platilo: a opr (b opr c) == (a opr b) opr c
. Pri asociatívnej funkcii platí: a opr b opr c opr d == (a opr b) opr (c opr d)
, tzn. paralelná verzia funkcie reduce môže výpočet rozdeliť a paralelne vypočítať medzivýsledky (a opr b)
a (c opr d)
a potom ich skombinovať volaním opr
do výslednej hodnoty. Pre hodnotu init
by malo ďalej platiť opr(init, x) = opr(x, init) = x
.
# pomocou reduce môžete vypočítať napr. sumu prvkov zoznamu (pre operáciu sčítania je init = 0)
sum = reduce(a, lambda x, y: x + y, 0) # výpočet pre [-1, 0, 1, 2, -3] zodpovedá (((((0 + -1) + 0) + 1) + 2) + -3) = -1
# funkcie filter, map a reduce môžete kombinovať pre výpočet zložitejších funkcií
# napr. pre výpočet sumy štvorcov kladných prvkov a:
b = filter(a, lambda x: x > 0) # najprv odfiltrujeme iba kladné prvky
b = map(b, lambda x: x * x) # vypočítame mocniny
sum = reduce(b, lambda x, y: x + y, 0) # a spočítame ich sumu
# pomocou kombinácie map a reduce môžete vypočítať aj viacero štatistík naraz
# napr. ak chceme vypočítať počet a sumu prvkov zoznamu a:
# najprv transformujeme a na zoznam dvojíc, kde prvá zložka dvojice bude vždy 1 a druhá prvok z a
b = map(a, lambda x: (1, x)) # = [(1, -1), (1, 0), (1, 1), (1, 2), (1, -3)]
# parametre x a y funkcie opr budú dvojice, v prvej zložke budeme postupne pripočítavať jednotky a v druhej prvky zoznamu a
# ako počiatočnú hodnotu nastavíme dvojicu (0, 0)
count_sum = reduce(b, lambda x, y: (x[0] + y[0], x[1] + y[1]), (0, 0)) # vypíše sa dvojica (počet prvkov, suma)
count_sum
Moduly¶
Zložitejšie skripty si môžete rozdeliť do viacerých súborov, ktoré potom môžete importovať ako samostatné moduly. Napr. ak chcete využívať vo svojom zápisníku funkcie z nasledujúceho príkladu, skopírujte kód do samostatného súboru, ktorý uložíte do rovnakého adresára v akom je súbor vášho zápisníka (python5.ipynb
). Názov súboru zvoľte v tvare [názov modulu].py
(napr.example_module.py
):
# v súbore modulu si definujeme jednoduché funkcie
def non_zero(x):
"""Funkcia testuje, či je hodnota parametra x nenulová"""
return x != 0 # vráti sa True ak x != 0, inak False
def is_positive(x)
"""Funkcia testuje, či je hodnota parametra x kladné číslo, alebo 0"""
return x >= 0
print("10 is positive?: ", is_positive(10))
V skripte potom môžete naimportovať funkcie modulu príkazom import [názov modulu]
, napr.:
# naimportujeme modul, ktorý je uložený v súbore ‘example_module.py’
import example_module
# ak interpreter nenájde súbor s názvom modulu, príkaz skončí chybou ImportError
# pri prvom importovaní modulu do vášho skriptu interpreter vykoná všetky príkazy modulu (tzn. napr., že pre ‘example_module.py’ sa na obrazovke
# vypíše výpis z volania funkcie print na poslednom riadku)
# na všetky názvy definované v module sa musíte odkazovať cez meno modulu, napr. pre volanie funkcie non_zero(x) musíte zadať:
example_module.non_zero(5)
# ak chcete importovať funkciu non_zero pod lokálnym menom, v skripte použite príkaz:
from example_module import non_zero
# ak ste už vo vašom skripte definovali funkciu s menom non_zero, jej definícia sa prepíše verziou zo skriptu
# (týmto spôsobom môžete predefinovať aj štandardné funkcie poskytované jazykom Python!)
# príkazom import môžete naimportovať aj viacero funkcií naraz, napr.:
from example_module import non_zero, is_positive
# pod lokálnym menom sme importovali funkcie non_zero, filter, map a reduce
print("10 is non zero:", non_zero(10))
Úlohy¶
Úloha 5.1¶
Napíšte funkciu find_value(l, value)
, ktorá vráti pozíciu prvého výskytu prvku zoznamu l
so zadanou hodnotou value
, alebo -1 ak sa taký prvok v zozname nenachádza.
Úloha 5.2¶
Napíšte funkciu count_values(l)
, ktorá spočíta koľkokrát sa vyskytovali rôzne hodnoty v zozname l
a vráti mapu s dvojicami (hodnota, početnosť). Pri riešení využite kód z úlohy 4.3.
Úloha 5.3¶
Upravte funkciu find_values
z úlohy 5.1 tak, že pridáte parameter default_index
s prednastavenou hodnotou -1, ktorého hodnota sa vráti ak sa hodnota value
v zozname nenájde.
Úloha 5.4¶
Rozdeľte riešenie úlohy 3.3 na jednoduchšie podúlohy pre ktoré naprogramujte potrebné funkcie.
Úloha 5.5¶
Rozdeľte riešenie úlohy 4.5 na jednoduchšie podúlohy pre ktoré naprogramujte potrebné funkcie.