Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Chyby, výjimky a logování

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 logger

Vý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 zero

Chytá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() za logger.info() / logger.debug().

  • Logujte do souboru při dlouhých výpočtech (neztrácejte výstupy).

  • Používejte @logger.catch nebo logger.exception() místo ručního vypisování tracebacků.