Chyby v Pythonu rozlišujeme na syntaktické chyby a chyby za běhu (run-time). Syntaktické chyby (nespárované závorky, špatné odsazení apod.) zabrání spuštění programu úplně. Run-time chyby vznikají nesprávným použitím funkce, chybějícími daty apod. — projeví se až při běhu.
Chyby za běhu Python signalizuje mechanismem výjimek (exceptions), který si ukážeme v první části. Souběžně budeme používat knihovnu Loguru pro logování — systematické zaznamenávání toho, co program dělá. Logování je od začátku lepší volba než print(): zprávy nesou čas, úroveň závažnosti i pozici v kódu, lze je filtrovat a ukládat do souboru. Loguru je jednodušší na použití než vestavěný logging. Zároveň toho umí více (například strukturované logování).
import sys
from loguru import loggerVýjimka (exception) je vyhozena ve chvíli, kdy dojde k chybě. Pokud tuto výjimku nezachytíme (viz dále), běh programu se přeruší. Např. dělení nulou skončí výjimkou ZeroDivisionError:
1/0---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
Cell In[2], line 1
----> 1 1/0
ZeroDivisionError: division by zeroChytáme výjimky¶
Pokud nechceme, aby běh programu skončil ve chvíli výjimky, můžeme použít try - except blok. Ten funguje tak, že rizikovou část kód umístíme do try bloku, do except bloku pak umístíme instrukce pro případ chyby (výjimky).
try:
1/0
except:
logger.error("nulou se nedělí!")2026-02-21 16:54:29.713 | ERROR | __main__:<module>:4 - nulou se nedělí!
Takto použitý except odchytí všechny výjimky. To není obvykle dobrá praktika, je lepší odchytávat pouze určité výjimky (takové, které očekáváme, že mohou nastat). Pro odchycení dělení nulou by to vypadalo asi takto:
try:
1/0
# do proměnné e se uloží vyhozená výjimka
except ZeroDivisionError as e:
logger.error(f"nulou se nedělí! ({e})")2026-02-21 16:54:30.352 | ERROR | __main__:<module>:5 - nulou se nedělí! (division by zero)
Kompletní try-except blok může ještě obsahovat else a finally bloky, viz dokumentace. finally se hodí zejména pro “úklid”, např. zavření souboru apod.
Vyhazujeme výjimky¶
Výjimku můžeme samozřejmě vyhodit i v našem kódu pomocí klíčového slova raise. Pokud bychom chtěli např. kontrolovat vstup nějaké funkce, uděláme to takto:
def fact(n):
"""Spočítá faktoriál
"""
from math import factorial
try:
# zkusíme převést n na číslo
n = float(n)
except ValueError as e:
raise ValueError("{} není číslo".format(n))
# je n celé číslo >= 0
if not n.is_integer() or n < 0:
raise ValueError("{} není celé číslo >= 0".format(n))
else:
n = int(n)
return factorial(n)
# jednoduchý test
n = 4
print(f"{n}! = {fact(n)}")4! = 24
# teď zkusíme, jestli fungují naše výjimky
for n in (4.0, "0", 3.2, -1):
try:
print(f"{n}! = {fact(n)}")
# Exception odchytí v podstatě jakoukoli výjimku, ostatní výjimky totiž od ní dědí
except Exception as e:
logger.warning(str(e))2026-02-21 16:54:32.457 | WARNING | __main__:<module>:7 - 3.2 není celé číslo >= 0
2026-02-21 16:54:32.457 | WARNING | __main__:<module>:7 - -1.0 není celé číslo >= 0
4.0! = 24
0! = 1
Traceback a logger.exception()¶
Chceme-li v bloku except zalogovat celý traceback výjimky, použijeme logger.exception(). Je to ekvivalent logger.error(), který navíc automaticky připojí traceback aktuální výjimky — bez nutnosti importovat modul traceback:
try:
fact(1.1)
except Exception:
# logger.exception() = logger.error() + automatický traceback aktuální výjimky
logger.exception("Zachycena výjimka:")2026-02-21 16:54:34.456 | ERROR | __main__:<module>:5 - Zachycena výjimka:
Traceback (most recent call last):
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "/Users/jakub/workspace/fjfi/python-fjfi/.venv/lib/python3.12/site-packages/ipykernel_launcher.py", line 18, in <module>
app.launch_new_instance()
│ └ <bound method Application.launch_instance of <class 'ipykernel.kernelapp.IPKernelApp'>>
└ <module 'ipykernel.kernelapp' from '/Users/jakub/workspace/fjfi/python-fjfi/.venv/lib/python3.12/site-packages/ipykernel/kern...
File "/Users/jakub/workspace/fjfi/python-fjfi/.venv/lib/python3.12/site-packages/traitlets/config/application.py", line 1075, in launch_instance
app.start()
│ └ <function IPKernelApp.start at 0x10c3ff2e0>
└ <ipykernel.kernelapp.IPKernelApp object at 0x1057a1e20>
File "/Users/jakub/workspace/fjfi/python-fjfi/.venv/lib/python3.12/site-packages/ipykernel/kernelapp.py", line 758, in start
self.io_loop.start()
│ │ └ <function BaseAsyncIOLoop.start at 0x10c42dd00>
│ └ <tornado.platform.asyncio.AsyncIOMainLoop object at 0x10ca4a780>
└ <ipykernel.kernelapp.IPKernelApp object at 0x1057a1e20>
File "/Users/jakub/workspace/fjfi/python-fjfi/.venv/lib/python3.12/site-packages/tornado/platform/asyncio.py", line 211, in start
self.asyncio_loop.run_forever()
│ │ └ <function BaseEventLoop.run_forever at 0x105cc5940>
│ └ <_UnixSelectorEventLoop running=True closed=False debug=False>
└ <tornado.platform.asyncio.AsyncIOMainLoop object at 0x10ca4a780>
File "/Users/jakub/.local/share/uv/python/cpython-3.12.12-macos-aarch64-none/lib/python3.12/asyncio/base_events.py", line 645, in run_forever
self._run_once()
│ └ <function BaseEventLoop._run_once at 0x105cc7740>
└ <_UnixSelectorEventLoop running=True closed=False debug=False>
File "/Users/jakub/.local/share/uv/python/cpython-3.12.12-macos-aarch64-none/lib/python3.12/asyncio/base_events.py", line 1999, in _run_once
handle._run()
│ └ <function Handle._run at 0x105c4b1a0>
└ <Handle <_asyncio.TaskStepMethWrapper object at 0x10cadbe50>()>
File "/Users/jakub/.local/share/uv/python/cpython-3.12.12-macos-aarch64-none/lib/python3.12/asyncio/events.py", line 88, in _run
self._context.run(self._callback, *self._args)
│ │ │ │ │ └ <member '_args' of 'Handle' objects>
│ │ │ │ └ <Handle <_asyncio.TaskStepMethWrapper object at 0x10cadbe50>()>
│ │ │ └ <member '_callback' of 'Handle' objects>
│ │ └ <Handle <_asyncio.TaskStepMethWrapper object at 0x10cadbe50>()>
│ └ <member '_context' of 'Handle' objects>
└ <Handle <_asyncio.TaskStepMethWrapper object at 0x10cadbe50>()>
File "/Users/jakub/workspace/fjfi/python-fjfi/.venv/lib/python3.12/site-packages/ipykernel/kernelbase.py", line 614, in shell_main
await self.dispatch_shell(msg, subshell_id=subshell_id)
│ │ │ └ None
│ │ └ [<zmq.Frame(b'02b7b741-ea7'...36B)>, <zmq.Frame(b'<IDS|MSG>')>, <zmq.Frame(b'b1f77040e729'...64B)>, <zmq.Frame(b'{"date":"202...
│ └ <function Kernel.dispatch_shell at 0x10c38c720>
└ <ipykernel.ipkernel.IPythonKernel object at 0x10c4142f0>
File "/Users/jakub/workspace/fjfi/python-fjfi/.venv/lib/python3.12/site-packages/ipykernel/kernelbase.py", line 471, in dispatch_shell
await result
└ <coroutine object IPythonKernel.execute_request at 0x10c862890>
File "/Users/jakub/workspace/fjfi/python-fjfi/.venv/lib/python3.12/site-packages/ipykernel/ipkernel.py", line 366, in execute_request
await super().execute_request(stream, ident, parent)
│ │ └ {'header': {'date': datetime.datetime(2026, 2, 21, 15, 54, 34, 454000, tzinfo=tzutc()), 'msg_id': '4bb553ee-29fd-4922-82f0-4e...
│ └ [b'02b7b741-ea70-4219-a4fe-7080f10ab955']
└ <zmq.Socket(zmq.PAIR) at 0x10c9e7540>
File "/Users/jakub/workspace/fjfi/python-fjfi/.venv/lib/python3.12/site-packages/ipykernel/kernelbase.py", line 827, in execute_request
reply_content = await reply_content
└ <coroutine object IPythonKernel.do_execute at 0x10c3bd7b0>
File "/Users/jakub/workspace/fjfi/python-fjfi/.venv/lib/python3.12/site-packages/ipykernel/ipkernel.py", line 458, in do_execute
res = shell.run_cell(
│ └ <function ZMQInteractiveShell.run_cell at 0x10c3d16c0>
└ <ipykernel.zmqshell.ZMQInteractiveShell object at 0x10c427440>
File "/Users/jakub/workspace/fjfi/python-fjfi/.venv/lib/python3.12/site-packages/ipykernel/zmqshell.py", line 663, in run_cell
return super().run_cell(*args, **kwargs)
│ └ {'store_history': True, 'silent': False, 'cell_id': 'vscode-notebook-cell:/Users/jakub/workspace/fjfi/python-fjfi/numerical_p...
└ ('try:\n fact(1.1)\nexcept Exception:\n # logger.exception() = logger.error() + automatický traceback aktuální výjimky\...
File "/Users/jakub/workspace/fjfi/python-fjfi/.venv/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3123, in run_cell
result = self._run_cell(
│ └ <function InteractiveShell._run_cell at 0x10ba1c720>
└ <ipykernel.zmqshell.ZMQInteractiveShell object at 0x10c427440>
File "/Users/jakub/workspace/fjfi/python-fjfi/.venv/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3178, in _run_cell
result = runner(coro)
│ └ <coroutine object InteractiveShell.run_cell_async at 0x10c86be00>
└ <function _pseudo_sync_runner at 0x10b9f76a0>
File "/Users/jakub/workspace/fjfi/python-fjfi/.venv/lib/python3.12/site-packages/IPython/core/async_helpers.py", line 128, in _pseudo_sync_runner
coro.send(None)
│ └ <method 'send' of 'coroutine' objects>
└ <coroutine object InteractiveShell.run_cell_async at 0x10c86be00>
File "/Users/jakub/workspace/fjfi/python-fjfi/.venv/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3400, in run_cell_async
has_raised = await self.run_ast_nodes(code_ast.body, cell_name,
│ │ │ │ └ '/var/folders/60/809c1h1n755_llm92lr0r3040000gn/T/ipykernel_31678/34902820.py'
│ │ │ └ [<ast.Try object at 0x11310f890>]
│ │ └ <ast.Module object at 0x11310f710>
│ └ <function InteractiveShell.run_ast_nodes at 0x10ba1cae0>
└ <ipykernel.zmqshell.ZMQInteractiveShell object at 0x10c427440>
File "/Users/jakub/workspace/fjfi/python-fjfi/.venv/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3641, in run_ast_nodes
if await self.run_code(code, result, async_=asy):
│ │ │ │ └ False
│ │ │ └ <ExecutionResult object at 10cbe7590, execution_count=7 error_before_exec=None error_in_exec=None info=<ExecutionInfo object ...
│ │ └ <code object <module> at 0x10cacb880, file "/var/folders/60/809c1h1n755_llm92lr0r3040000gn/T/ipykernel_31678/34902820.py", li...
│ └ <function InteractiveShell.run_code at 0x10ba1cb80>
└ <ipykernel.zmqshell.ZMQInteractiveShell object at 0x10c427440>
File "/Users/jakub/workspace/fjfi/python-fjfi/.venv/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3701, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
│ │ │ │ └ <property object at 0x10ba147c0>
│ │ │ └ <ipykernel.zmqshell.ZMQInteractiveShell object at 0x10c427440>
│ │ └ <property object at 0x10ba14860>
│ └ <ipykernel.zmqshell.ZMQInteractiveShell object at 0x10c427440>
└ <code object <module> at 0x10cacb880, file "/var/folders/60/809c1h1n755_llm92lr0r3040000gn/T/ipykernel_31678/34902820.py", li...
> File "/var/folders/60/809c1h1n755_llm92lr0r3040000gn/T/ipykernel_31678/34902820.py", line 2, in <module>
fact(1.1)
└ <function fact at 0x10ca68720>
File "/var/folders/60/809c1h1n755_llm92lr0r3040000gn/T/ipykernel_31678/1769091114.py", line 12, in fact
raise ValueError("{} není celé číslo >= 0".format(n))
└ 1.1
ValueError: 1.1 není celé číslo >= 0
Logování do souboru¶
Logy z dlouhých výpočtů chceme uchovávat v souboru. Loguru to umožňuje jednoduše přidáním dalšího sink (výstupu). Zároveň lze nastavit automatické otáčení souboru (rotation) a mazání starých záznamů (retention).
# Přidáme výstup do souboru
# rotation="10 MB" -- vytvoří nový soubor, jakmile aktuální přesáhne 10 MB
# retention="7 days" -- automaticky smaže záznamy starší 7 dní
logger.add(
"vypocet.log",
level="DEBUG",
rotation="10 MB",
retention="7 days",
encoding="utf-8",
)
logger.info("Spouštím výpočet...")
for i in range(3):
logger.debug(f"Iterace {i}")
logger.success("Výpočet dokončen.")2026-02-21 16:54:37.074 | INFO | __main__:<module>:12 - Spouštím výpočet...
2026-02-21 16:54:37.074 | DEBUG | __main__:<module>:14 - Iterace 0
2026-02-21 16:54:37.075 | DEBUG | __main__:<module>:14 - Iterace 1
2026-02-21 16:54:37.075 | DEBUG | __main__:<module>:14 - Iterace 2
2026-02-21 16:54:37.076 | SUCCESS | __main__:<module>:15 - Výpočet dokončen.
# Zobrazíme obsah souboru
with open("vypocet.log", encoding="utf-8") as f:
print(f.read())2026-02-21 16:54:37.074 | INFO | __main__:<module>:12 - Spouštím výpočet...
2026-02-21 16:54:37.074 | DEBUG | __main__:<module>:14 - Iterace 0
2026-02-21 16:54:37.075 | DEBUG | __main__:<module>:14 - Iterace 1
2026-02-21 16:54:37.075 | DEBUG | __main__:<module>:14 - Iterace 2
2026-02-21 16:54:37.076 | SUCCESS | __main__:<module>:15 - Výpočet dokončen.
Pozor: logger.add přidá vždy další výstup. Pokud chceme výstupy nejprve odstranit, použijeme logger.remove().
Doporučení pro vědecké skripty¶
Nahraďte
print()zalogger.info()/logger.debug().Logujte do souboru při dlouhých výpočtech (neztrácejte výstupy).
Používejte
@logger.catchnebologger.exception()místo ručního vypisování tracebacků.