17. Výnimky¶
Zapíšme funkciu, ktorá prečíta celé číslo zo vstupu:
def cislo(): vstup = input('zadaj cislo: ') return int(vstup)>>> cislo() zadaj cislo: 234 234
Toto funguje, len ak zadáme korektný reťazec celého čísla. Spadne to s chybovou správou pri zle zadanom vstupe:
>>> cislo() zadaj cislo: 234a ... ValueError: invalid literal for int() with base 10: '234a'
Aby takýto prípad nenastal, vložíme pred volanie funkcie int() test, napr. takto
def test_cele_cislo(retazec): for znak in retazec: if znak not in '0123456789': return False return True def cislo(): vstup = input('zadaj cislo: ') if test_cele_cislo(vstup): return int(vstup) print('chybne zadane cele cislo')
Pripadne s opakovaným vstupom pri chybne zadanom čísle (hoci aj tento test test_cele_cislo() nie je dokonalý a niekedy prejde, aj keď nemá):
def cislo(): while True: vstup = input('zadaj cislo: ') if test_cele_cislo(vstup): return int(vstup) print('*** chybne zadane cele cislo ***')
Takto ošetrený vstup už nespadne, ale oznámi chybu a pýta si nový vstup, napr.
>>> cislo() zadaj cislo: 234a *** chybne zadane cele cislo *** zadaj cislo: 234 a *** chybne zadane cele cislo *** zadaj cislo: 234 234 >>>
17.1. try - except¶
Python umožňuje aj iný spôsob riešenia takýchto situácií: chybe sa nebudeme snažiť predísť, ale keď vznikne, tak ju “ošetríme”. Využijeme novú programovú konštrukciu try - except. Jej základný tvar je
try: '''blok príkazov''' except MenoChyby: '''ošetrenie chyby'''
Konštrukcia sa skladá z dvoch častí:
- príkazy medzi
tryaexcept - príkazmi za
except
Blok príkazov medzi try a except bude Python spúšťať “opatrnejšie”, t.j. ak pri ich vykonávaní nastane uvedená chyba (meno chyby za except), vykonávanie bloku príkazov sa okamžite ukončí a pokračuje sa príkazmi za except, pritom Python zruší chybový stav, v ktorom sa práve nachádzal. Ďalej sa pokračuje v príkazoch za touto konštrukciou.
Ak pri opatrnejšom vykonávaní bloku príkazov uvedená chyba nenastane, tak príkazy za except sa preskočia a normálne sa pokračuje v príkazoch za konštrukciou.
Ak pri opatrnejšom vykonávaní bloku príkazov nastane iná chyba ako je uvedená v riadku except, tak táto konštrukcia túto chybu nespracuje, ale pokračuje sa tak, ako sme boli zvyknutí doteraz, t.j. celý program spadne a IDLE o tom vypíše chybovú správu.
Ukážme to na predchádzajúcom príklade (pomocnú funkciu test_cele_cislo() teraz už nepotrebujeme):
def cislo(): while True: vstup = input('zadaj cislo: ') try: return int(vstup) except ValueError: print('*** chybne zadane cele cislo ***')
To isté by sa dalo zapísať aj niekoľkými inými spôsobmi, napr.
def cislo(): while True: try: return int(input('zadaj cislo: ')) except ValueError: print('*** chybne zadane cele cislo ***')def cislo(): while True: try: vysledok = int(input('zadaj cislo: ')) break except ValueError: print('*** chybne zadane cele cislo ***') return vysledokdef cislo(): ok = False while not ok: try: vysledok = int(input('zadaj cislo: ')) ok = True except ValueError: print('*** chybne zadane cele cislo ***') return vysledok
Na chybové prípady odteraz nemusíme pozerať ako na niečo zlé, ale ako na výnimočné prípady (výnimky, t.j. exception), ktoré vieme veľmi šikovne vyriešiť. Len neošetrená výnimka spôsobí spadnutie nášho programu. Často to bude znamenať, že sme niečo zle naprogramovali, alebo sme nedomysleli nejaký špeciálny prípad.
Na predchádzajúcom príklade sme videli, že odteraz bude pre nás dôležité meno chyby (napr. ako v predchádzajúcom príklade ValueError). Mená chýb nám prezradí Python, keď vyskúšame niektoré konkrétne situácie, napr.
>>> 1+'2' ... TypeError: unsupported operand type(s) for +: 'int' and 'str' >>> 12/0 ... ZeroDivisionError: division by zero >>> x+1 ... NameError: name 'x' is not defined >>> open('') ... FileNotFoundError: [Errno 2] No such file or directory: '' >>> [1,2,3][10] ... IndexError: list index out of range >>> 5() ... TypeError: 'int' object is not callable >>> ''.x ... AttributeError: 'str' object has no attribute 'x' >>> 2**10000/1. ... OverflowError: int too large to convert to float >>> import x ... ImportError: No module named 'x' >>> def t(): x += 1 >>> t() ... UnboundLocalError: local variable 'x' referenced before assignment
Všimnite si, že Python za meno chyby vypisuje aj nejaký komentár, ktorý nám môže pomôcť pri pochopení dôvodu chyby, resp. pri ladení. Tento text je ale mimo mena chyby, v except riadku ho nepíšeme. Takže, ak chceme odchytiť a spracovať nejakú konkrétnu chybu, jej meno si najjednoduchšie zistíme v dialógovom režime v IDLE.
17.1.1. Spracovanie viacerých výnimiek¶
Pomocou try a except môžeme zachytiť aj viac chýb ako jednu. V ďalšom príklade si funkcia vyžiada celé číslo, ktoré bude indexom do nejakého poľa. Funkcia potom vypíše hodnotu prvku s týmto indexom. Môžu tu nastať dve rôzne výnimky:
- ValueError pre zle zadané celé číslo indexu
- IndexError pre index mimo rozsah poľa
Zapíšme funkciu:
pole = ['prvy', 'druhy', 'treti', 'stvrty'] def zisti(): while True: try: vstup = input('zadaj index: ') index = int(vstup) print('prvok pola =', pole[index]) break except ValueError: print('*** chybne zadane cele cislo ***') except IndexError: print('*** index mimo rozsah pola ***')
otestujeme:
>>> zisti() zadaj index: 22 *** index mimo rozsah pola *** zadaj index: 2. *** chybne zadane cele cislo *** zadaj index: 2 prvok pola = treti >>>
To isté by sme dosiahli aj vtedy, keby sme to zapísali pomocou dvoch vnorených príkazov try:
def zisti(): while True: try: try: vstup = input('zadaj index: ') index = int(vstup) print('prvok pola =', pole[index]) break except ValueError: print('*** chybne zadane cele cislo ***') except IndexError: print('*** index mimo rozsah pola ***')
17.1.2. Zlúčenie výnimiek¶
Niekedy sa môže hodiť, keď máme pre rôzne výnimky spoločný kód. Za except môžeme uviesť aj viac rôznych mien výnimiek, ale musíme ich uzavrieť do zátvoriek (urobiť z nich tuple), napr.
def zisti(): while True: try: print('prvok pola =', pole[int(input('zadaj index: '))]) break except (ValueError, IndexError): print('*** chybne zadany index pola ***')>>> zisti() zadaj index: 22 *** chybne zadany index pola *** zadaj index: 2. *** chybne zadany index pola *** zadaj index: 2 prvok pola = treti >>>
Uvedomte si, že pri takomto zlučovaní výnimiek môžeme stratiť detailnejšiu informáciu o tom, čo sa v skutočnosti udialo.
Príkaz try - except môžeme použiť aj bez uvedenia mena chyby: vtedy to označuje zachytenie všetkých typov chýb, napr.
def zisti(): while True: try: print('prvok pola =', pole[int(input('zadaj index: '))]) break except: print('*** chybne zadany index pola ***')
Takýto spôsob použitia try - except sa ale neodporúča, skúste sa ho vyvarovať! Jeho používaním môžete ušetriť zopár minút pri hľadaní všetkých typov chýb, ktoré môžu vzniknúť pri vykonávaní daného bloku príkazov. Ale skúsenosti ukazujú, že môžete zase stratiť niekoľko hodín pri hľadaní chýb v takýchto programoch. Veľmi často takéto bloky try - except bez uvedenia výnimky sú zdrojom veľmi nečakaných chýb.
17.1.3. Ako funguje mechanizmus výnimiek¶
Kým sme nepoznali výnimky, ak nastala nejaká chyba v našej funkcii, dostali sme nejaký takýto výpis:
>>> fun1() Traceback (most recent call last): File "<pyshell#9>", line 1, in <module> fun1() File "p.py", line 13, in fun1 fun2() File "p.py", line 16, in fun2 fun3() File "p.py", line 19, in fun3 fun4() File "p.py", line 22, in fun4 int('x') ValueError: invalid literal for int() with base 10: 'x'
Python pri výskyte chyby (t.j. nejakej výnimky) hneď túto chybu nevypisuje, ale zisťuje, či sa nevyskytla v bloku príkazu try - except. Ak áno a meno chyby zodpovedá menu v except, vykoná definované príkazy pre túto výnimku.
Ak na danom mieste neexistuje obsluha tejto výnimky, vyskočí z momentálnej funkcie a zisťuje, či jej volanie v nadradenej funkcii nebolo chránené príkazom try - except. Ak áno, vykoná čo treba a na tomto mieste pokračuje ďalej, akoby sa žiadna chyba nevyskytla.
Ak ale ani v tejto funkcii nie je kontrola pomocou try - except, vyskakuje o úroveň vyššie a vyššie, až kým nepríde na najvyššiu úroveň, teda do dialógu IDLE. Keďže nik doteraz nezachytil túto výnimku, IDLE ju vypíše v nám známom tvare. V tomto výpise vidíme, ako sa Python “vynáral” vyššie a vyššie.
17.1.4. Práca so súbormi¶
Pri práci so súbormi výnimky vznikajú veľmi často a nie je jednoduché ošetriť všetky situácie pomocou podmienených príkazov. Najčastejšou chybou je neexistujúci súbor:
try: with open('x.txt') as subor: cislo = int(subor.readline()) except FileNotFoundError: print('*** neexistujuci subor ***') cislo = 0 except (ValueError, TypeError): print('*** prvy riadok suboru neobsahuje cele cislo ***') cislo = 10
Prípadne sa môže hodiť pomocná funkcia, ktorá zistí, či súbor s daným menom existuje:
def existuje(meno_suboru): try: with open(meno_suboru): return True except (TypeError, OSError, FileNotFoundError): return False
Uvedomte si ale, že táto funkcia, aby zistila, či súbor existuje, ho otvorí a okamžite aj zatvorí. Preto takýto kód nebude veľmi efektívny:
if existuje('x.txt'): with open('x.txt') as t: obsah = t.read() else: obsah = ''
17.2. Vyvolanie výnimky¶
V niektorých situáciách sa nám môže hodiť vyvolanie vzniknutej chyby aj napriek tomu, že ju vieme zachytiť príkazom try - except. Slúži na to nový príkaz raise, ktorý má niekoľko variantov. Prvý z nich môžete vidieť v upravenej verzii funkcie cislo(). Funkcia sa najprv 3-krát pokúsi prečítať číslo zo vstupu, a ak sa jej to napriek tomu nepodarí, rezignuje a vyvolá známu chybu ValueError:
def cislo(): pokus = 0 while True: try: return int(input('zadaj cislo: ')) except ValueError: pokus += 1 if pokus > 3: raise print('*** chybne zadane cele cislo ***')>>> cislo() zadaj cislo: jeden *** chybne zadane cele cislo *** zadaj cislo: dva *** chybne zadane cele cislo *** zadaj cislo: tri *** chybne zadane cele cislo *** zadaj cislo: styri ... ValueError: invalid literal for int() with base 10: 'styri'
Pomocou príkazu raise môžeme vyvolať nielen práve zachytenú výnimku, ale môžeme vyvolať ľubovoľnú inú chybu aj s vlastným komentárom, ktorý sa pri nej vypíše, napr.
raise ValueError('chybne zadane cele cislo') raise ZeroDivisionError('delenie nulou') raise TypeError('dnes sa ti vobec nedari')
17.2.1. Príklad s metódou index()¶
Poznáme už metódu index(), ktorá v poli (typ list ale funguje aj pre znakové reťazce) nájde prvý výskyt nejakej hodnoty. Metóda je zaujímavá tým, že vyvolá výnimku ValueError, ak sa táto hodnota v poli nenachádza. Kým sme nepoznali odchytávanie výnimiek, väčšinou sme museli najprv kontrolovať, či sa tam príslušný prvok nachádza a až ak áno, volali sme index(), napr.
def nahrad(pole, h1, h2): if h1 in pole: i = pole.index(h1) pole[i] = h2
Pomocou try - except to vyriešime výrazne efektívnejšie:
def nahrad(pole, h1, h2): try: i = pole.index(h1) pole[i] = h2 except ValueError: pass
Táto metóda index(), ktorá funguje pre jednorozmerné polia, nás môže inšpirovať aj na úlohu, v ktorej budeme hľadať indexy do dvojrozmerného poľa. Napíšme funkciu hladaj(pole, hodnota), ktorá hľadá prvý výskyt danej hodnoty v dvojrozmernom poli a ak taký prvok nájde, vráti jeho číslo riadku a číslo stĺpca. Ak sa tam taký prvok nenachádza, funkcia by mala vyvolať rovnakú výnimku, ako to robila pôvodná metóda index(), t.j. ValueError: hodnota is not in list. Zapíšme riešenie dvoma vnorenými cyklami:
def hladaj(pole, hodnota): for r in range(len(pole)): for s in range(len(pole[r])): if pole[r][s] == hodnota: return r, s raise ValueError(repr(hodnota) + ' is not in list')
Hoci je toto správne riešenie, vieme ho zapísať aj efektívnejšie pomocou volania metódy index():
def hladaj(pole, hodnota): for r in range(len(pole)): try: s = pole[r].index(hodnota) return r, s except ValueError: pass raise ValueError(repr(hodnota) + ' is not in list')
Ak si ale uvedomíme, že neúspešné hľadanie prvku v r-tom riadku poľa pomocou index() vyvolá presne tú istú chybu, ktorú sme zachytili a potom znovu vyvolali, môžeme to celé skrátiť takto:
def hladaj(pole, hodnota): for r in range(len(pole)): try: s = pole[r].index(hodnota) return r, s except ValueError: if r == len(pole)-1: raise
Teda zachytená chyba ValueError v poslednom riadku dvojrozmerného poľa označuje, že sa hodnota nenachádza v žiadnom riadku poľa a teda sa opätovne vyvolá zachytená chyba. (Zamyslite sa, ako bude toto riešenie fungovať pre prázdne dvojrozmerné pole, teda pole, ktoré neobsahuje ani jeden riadok).
17.2.2. Vytváranie vlastných výnimiek¶
Keď chceme vytvoriť vlastný typ výnimky, musíme vytvoriť novú triedu odvodenú od základnej triedy Exception. Môže to vyzerať napr. takto:
class MojaChyba(Exception): pass
Príkaz pass tu znamená, že nedefinujeme nič nové oproti základnej triede Exception. Použiť to môžeme napr. takto:
def podiel(p1, p2): if not isinstance(p1, int): raise MojaChyba('prvy parameter nie je cele cislo') if not isinstance(p2, int): raise MojaChyba('druhy parameter nie je cele cislo') if p2 == 0: raise MojaChyba('neda sa delit nulou') return p1//p2>>> podiel(22, 3) 7 >>> podiel(2.2, 3) ... MojaChyba: prvy parameter nie je cele cislo >>> podiel(22, 3.3) ... MojaChyba: druhy parameter nie je cele cislo >>> podiel(22, 0) ... MojaChyba: neda sa delit nulou >>>
17.2.3. Kontrola pomocou assert¶
Ďalší nový príkaz assert slúži na kontrolu nejakej podmienky: ak táto podmienka nie je splnená, vyvolá sa výnimka AssertionError aj s uvedeným komentárom. Tvar tohto príkazu je:
assert podmienka, 'komentár'
Toto sa často používa pri ladení, keď potrebujeme mať istotu, že je splnená nejaká konkrétna podmienka (vlastnosť). Prepíšme funkciu podiel() tak, že namiesto if a raise zapíšeme volanie assert:
def podiel(p1, p2): assert isinstance(p1, int), 'prvy parameter nie je cele cislo' assert isinstance(p2, int), 'druhy parameter nie je cele cislo' assert p2 != 0, 'neda sa delit nulou' return p1 // p2
17.2.4. Príklad s triedou Ucet¶
Na cvičeniach ste riešili príklad, v ktorom ste definovali triedu Ucet, resp. UcetHeslo aj jej metódy vklad() a vyber(). Ukážme riešenie trochu zjednodušeného zadania len s jednou triedou, zatiaľ bez ošetrovania výnimiek:
class Ucet: def __init__(self, meno, heslo, suma=0): self.meno, self.heslo, self.suma = meno, heslo, suma def __str__(self): return 'ucet {} -> {} euro'.format(self.meno, self.suma) def vklad(self, suma): if self.heslo == input('heslo pre {}? '.format(self.meno)): self.suma += suma else: print('chybne heslo') def vyber(self, suma): if self.heslo == input('heslo pre {}? '.format(self.meno)): if suma <= 0: return 0 suma = min(self.suma, suma) self.suma -= suma return suma else: print('chybne heslo') #---- test ---- mbank = Ucet('mbank', 'heslo1', 100) csob = Ucet('csob', 'heslo2', 30) print('*** stav uctov:', mbank, csob, sep='\n') mbank.vklad(csob.vyber(55))
Po spustení a zadaní hesiel, dostávame takýto výpis:
*** stav uctov: ucet mbank -> 100 euro ucet csob -> 30 euro heslo pre csob? heslo2 heslo pre mbank? heslo1 *** stav uctov: ucet mbank -> 130 euro ucet csob -> 0 euro
Zdá sa, že test prebehol v poriadku.
Prepíšme riešenie s využitím výnimiek. Zadefinujeme pritom vlastnú výnimku ChybnaTransakcia a budeme sa snažiť ošetriť všetky možné chybové situácie:
class ChybnaTransakcia(Exception): pass class Ucet: def __init__(self, meno, heslo, suma=0): self.meno, self.heslo, self.suma = meno, heslo, suma def __str__(self): return 'ucet {} -> {} euro'.format(self.meno, self.suma) def kontrola(self): if self.heslo and self.heslo != input('heslo pre {}? '.format(self.meno)): raise ChybnaTransakcia('chybne heslo pre vklad na ucet ' + self.meno) def vklad(self, suma): self.kontrola() try: if suma <= 0: raise TypeError self.suma += suma except TypeError: raise ChybnaTransakcia('chybne zadana suma pre vklad na ucet ' + self.meno) def vyber(self, suma): self.kontrola() try: if suma <= 0: raise TypeError suma = min(self.suma, suma) self.suma -= suma return suma except TypeError: raise ChybnaTransakcia('chybne zadana suma pre vyber z uctu ' + self.meno) def prevod(ucet1, ucet2, suma): '''prevedie sumu z ucet1 na ucet2''' suma = ucet1.vyber(suma) try: ucet2.vklad(suma) except ChybnaTransakcia: ucet1.suma += suma # vrati vybratu sumu na ucet1 raise #---- test ---- mbank = Ucet('mbank', 'heslo1', 100) csob = Ucet('csob', 'heslo2', 30) print('*** stav uctov:', mbank, csob, sep='\n') prevod(csob, mbank, 55) print('*** stav uctov:', mbank, csob, sep='\n')
Všimnite si, že pomocná funkcia prevod() sa snaží pri neúspešnej transakcii vrátiť vybratú sumu peňazí - hoci to nerobí úplne korektne ...
17.3. Cvičenie¶
Nájdite čo najviac rôznych chybových správ, ktoré môžu vzniknúť pri práci so znakovými reťazcami (hľadajte aj chybové správy s volaniami funkcií a metód).
- napr.
>>> 'abc'[3] IndexError: string index out of range >>> 'abc'[3] = 'a' TypeError: 'str' object does not support item assignment >>> ...
Napíšte funkcie
cele(hodnota)adesatinne(hodnota), ktoré prevedú danú hodnotu na celé číslo (funkciouint()), resp. desatinné (funkcioufloat()) a ak sa to nedá, funkcie vrátia nulu.- napr.
>>> cele(None) 0 >>> cele(3.14) 3 >>> desatinne('3,14') 0.0 >>> desatinne(abs) 0.0
Napíšte funkciu
priemer(pole), ktorá vypočíta priemer hodnôt v danom poli. Využite štandardnú funkciusum()a to či je pole prázdne netestujte príkazomifale odchyťte pomocoutry-except. Ak je pole neprázdne a nedá sa vypočítať súčet prvkov, funkciapriemer()vráti 0, ak je pole prázdne, funkcia vrátiNone.- napr.
>>> priemer([1.5, 2, 3.14, 4]) 2.66 >>> priemer([1, 2, [3], 4]) 0 >>> print(priemer([])) None
Napíšte funkciu
suma(pole), ktorá zistí číselný súčet prvkov poľa. Zrejme bude postupne pripočítavať prvky poľa a ak sa nejaký pripočítať nedá (neprejde operácia+), tento prvok vynechá.- napr.
>>> suma([1.5, 2, 3.14, 4]) 10.64 >>> suma([1, 2, [3], 4]) 7 >>> print(suma([])) 0
Napíšte funkciu
suma2(pole), ktorá zistí číselný súčet prvkov poľa. Ak je niektorý z prvkov pole (typlistalebotuple), funkcia sa rekurzívne zavolá na tomto prvku a jeho súčet pripočíta k výsledku. Ak sa nejaký prvok pripočítať nedá (neprejde operácia+), tento prvok vynechá.- napr.
>>> suma2([1, 2, '3', 4]) 7 >>> suma2([1, 2, [3], 4]) 10 >>> suma2([[], [1], 2, (3, 4)]) 10 >>> suma2([[[[42]]]]) 42 >>> suma2(((((5.5, 6.5))))) 12.0
Napíšte funkciu
pocet_riadkov(meno_suboru), ktorá vráti počet riadkov zadaného súboru. Ak daný súbor neexistuje (nepodaril saopen()), funkcia vráti-1.- napr.
>>> pocet_riadkov('cvicenie.py') 104 >>> pocet_riadkov('x.x') # pre neexistujuci subor -1
Napíšte funkciu
daj_cislo(meno_suboru, index, inak=0), ktorá predpokladá, že daný súbor má v každom riadku po jednom celom čísle. Funkcia vráti číselnú hodnotu z tohto riadka a ak sa to nedá (napr. súbor neexistuje, nemá dosť riadkov, nie je v tomto riadku iba jediná celočíselná hodnota), vráti hodnotu tretieho parametrainak.- napr.
>>> daj_cislo('cvicenie.py', 17, 'neviem') 'neviem'
Napíšte funkciu
sustavy(retazec), ktorá sa pokúsi daný reťazec previesť na číslo v rôznych číselných sústavách. Využite to, že štandardná funkciaint()môže byť zavolaná aj s druhým parametrom - číselnou sústavou, napr.int('ff',16)vráti 255, t.j.'ff'je v 16-ovej sústave číslo 255. Funkciasustavy()vráti 17-prvkové pole, pričom i-ty prvok poľa obsahuje prevod daného reťazca na číslo v i-sústave. Ak sa to pre nejakú sústavu urobiť nedá, prvok poľa na danom mieste bude mať hodnotuNone.- napr.
>>> sustavy('11') [11, None, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17] >>> sustavy('1a1') [None, None, None, None, None, None, None, None, None, None, None, 232, 265, 300, 337, 376, 417] >>> sustavy('FF') [None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, 255] >>> sustavy('x') [None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None]
Napíšte funkciu
ako(hodnota1, hodnota2), ktorá najprv zistí typ prvého parametrahodnota1a potom sa pokúsi pretypovať na tento typ druhý parameterhodnota2(zrejme volanímtyp(hodnota2)). Ak sa toto pretypovanie úspešne podarí, funkcia vráti túto pretypovanú hodnotu, inak vrátiNone.- napr.
>>> ako('a', 123) '123' >>> ako(3.1, 123) 123.0 >>> ako((), '123') ('1', '2', '3') >>> print(ako((), 123)) None
Napíšte funkciu
sucet(pole), ktorá spočíta všetky prvky daného poľa. Pracovať bude tak, že najprv zoberie prvý prvok poľa a ten priradíme dovyslako momentálny výsledok - k nemu budete postupne pripočítavať (použijete operáciu+) ďalšie prvky poľa. Lenže tieto ďalšie prvky v poli nemusia byť rovnakého typu ako prvý prvok a preto ich budete postupne pretypovávať na rovnaký typ a až pri úspešnom pretypovaní ich pripočítame k výsledkuvysl, inak ich idignorujete.
- napr.
>>> sucet([1, 2, 3.1, '4']) 10 >>> sucet([1., 2, 3.1, '4']) 10.1 >>> sucet([('p', 'y'), 'tho', ['n']]) ('p', 'y', 't', 'h', 'o', 'n') >>> sucet([1], (2, 3), 4) [1, 2, 3]