Debugowanie w Pythonie: pdb, breakpoint() i VS Code

Mateusz Bogolubow

02-11-2026

(aktualizacja: 02-11-2026)

Jak debugować Pythona: breakpoint(), pdb, post-mortem i pytest --pdb oraz VS Code. Z przykładem warunkowego breakpointu i listą powodów, dla których debugger się nie zatrzymuje.

Debugowanie w Pythonie: pdb, breakpoint() i VS Code
W Pythonie debugger uruchamiasz, wpisując breakpoint() w miejscu, w którym chcesz zatrzymać program, albo startując skrypt przez python -m pdb skrypt.py. W otwartym wierszu (Pdb) sprawdzasz zmienne poleceniem p, krokujesz przez n i s, a program wznawiasz przez c. To samo zrobisz w VS Code, klikając numer linii i naciskając F5.

Zanim zaczniesz: ten artykuł zakłada, że wiesz, czym jest debugger, breakpoint i krokowanie. Jeśli nie, zacznij od wprowadzenia do debuggera. Debugger w JavaScripcie opisuje osobny artykuł o debugowaniu w DevTools i VS Code. Tutaj: Python.

Jak uruchomić debugger w Pythonie?

Masz trzy sposoby, wszystkie z wbudowanego modułu pdb:

  1. breakpoint() w kodzie. Wpisujesz w miejscu, w którym program ma się zatrzymać, a Python (od wersji 3.7) uruchamia pdb:
def area(a, b):
    c = a * b
    breakpoint()
    return c
  1. python -m pdb skrypt.py. Uruchamia cały skrypt pod kontrolą debuggera, od pierwszej linii, bez zmian w kodzie. Breakpointy ustawiasz poleceniem b.
  2. Po awarii (post-mortem). Gdy program kończy się nieprzechwyconym wyjątkiem, python -m pdb skrypt.py wchodzi w debuggera automatycznie, w miejscu błędu.

Zatrzymany program pokazuje wiersz (Pdb), w którym wpisujesz polecenia.

Jak wyłączyć breakpoint() bez usuwania go z kodu?

Ustaw zmienną środowiskową PYTHONBREAKPOINT=0. Wszystkie wywołania breakpoint() są wtedy pomijane i program działa dalej:

PYTHONBREAKPOINT=0 python bp.py
12

To przydatne, gdy breakpoint() został w kodzie, a program musi chwilowo przejść bez zatrzymań (np. w skrypcie albo na serwerze). Nie zastępuje usunięcia go przed commitem. Ta sama zmienna pozwala podstawić inny debugger: wartość to ścieżka do funkcji, np. PYTHONBREAKPOINT=ipdb.set_trace, jeśli masz ipdb zainstalowany.

Jakie polecenia pdb warto znać? Tabela z odpowiednikami w VS Code

Pełna lista jest w dokumentacji, ale na co dzień wystarcza kilkanaście poleceń. Większość ma też skrót jednej litery:

Polecenie pdbCo robiOdpowiednik w VS Code
b plik.py:10ustawia breakpoint w linii 10klik na lewo od numeru linii
b 42, x > 10breakpoint warunkowy (conditional breakpoint)PPM na breakpoincie → Edit Breakpoint → Expression
cwznawia do następnego breakpointuF5
nwykonuje bieżącą linię (step over)F10
swchodzi do wywoływanej funkcji (step into)F11
rkończy bieżącą funkcję (step out)Shift+F11
untjedzie do następnej linii większej niż bieżąca, wychodząc z pętlipodobnie działa Run to Cursor w menu kontekstowym
p wyrażeniewypisuje wartośćpanel Variables lub Debug Console
pp wyrażeniewypisuje ładnie sformatowaną wartośćDebug Console
display wyrażeniepokazuje wartość po każdym kroku, jeśli się zmieniłapanel Watch
l / llpokazuje kod wokół bieżącej linii / całą funkcjęedytor z podświetloną linią
wpokazuje stos wywołań (call stack)panel Call Stack
u / dprzechodzi w górę / w dół stosuklik w ramkę w panelu Call Stack
apokazuje argumenty bieżącej funkcjipanel Variables
interactotwiera interaktywną konsolę w bieżącym zakresieDebug Console
!instrukcjawykonuje instrukcję Pythona w bieżącym zakresieDebug Console
qkończy debugowanie (program jest przerwany)Shift+F5

Skróty VS Code są domyślne i mogą się różnić zależnie od systemu i ustawień. Polecenie h w pdb wyświetla pomoc, a h polecenie opis jednego polecenia.

Jak znaleźć błąd widoczny tylko w jednej iteracji pętli? Przykład z warunkowym breakpointem

Funkcja liczy saldo konta na podstawie listy transakcji. W danych jest 200 transakcji, a wynik jest zły:

def final_balance(transactions):
    balance = 0
    for tx in transactions:
        if tx["type"] == "deposit":
            balance += tx["amount"]
        elif tx["type"] == "withdrawal":
            balance -= tx["amount"]
    return balance
from balance import final_balance

transactions = []
for i in range(200):
    transactions.append({"type": "deposit", "amount": 10})
transactions[137] = {"type": "refund", "amount": 25}

print(final_balance(transactions))
1990

Spodziewana suma to 2015 (199 wpłat po 10 i zwrot 25). Dwieście iteracji, a błąd dotyczy jednej. Breakpoint w każdej iteracji zatrzymywałby program dwieście razy, więc ustawiasz warunkowy, który zatrzyma się tylko wtedy, gdy typ transakcji jest inny niż oczekiwane:

python -m pdb run.py
(Pdb) b balance.py:4, tx["type"] not in ("deposit", "withdrawal")
Breakpoint 1 at balance.py:4
(Pdb) c
> balance.py(4)final_balance()
-> if tx["type"] == "deposit":
(Pdb) p tx
{'type': 'refund', 'amount': 25}
(Pdb) p balance
1370

Debugger zatrzymał się dokładnie na transakcji refund, a balance wynosi 1370 (137 wpłat po 10). Funkcja zna tylko deposit i withdrawal, a trzeci typ pomija bez ostrzeżenia. Poprawka może być różna (dodanie elif tx["type"] == "refund" albo rzucenie wyjątku dla nieznanego typu), ale przyczyna jest już widoczna i zapisana w jednym wywołaniu debuggera.

Jak debugować test, który się wywrócił? pytest --pdb i post-mortem

Gdy test pada z wyjątkiem, nie musisz zgadywać, w jakim stanie był program. pytest --pdb zatrzymuje się dokładnie w miejscu błędu i otwiera pdb (to właśnie debugowanie post-mortem, czyli „po awarii”). Przykładowy test:

from balance import final_balance


def test_amount_given_as_text():
    transactions = [
        {"type": "deposit", "amount": 100},
        {"type": "withdrawal", "amount": "30"},
    ]
    assert final_balance(transactions) == 70
pytest --pdb
...
E   TypeError: unsupported operand type(s) for -=: 'int' and 'str'
balance.py:7: TypeError
>>> entering PDB >>>
> balance.py(7)final_balance()
-> balance -= tx["amount"]
(Pdb) p tx["amount"]
'30'
(Pdb) up
> test_balance.py(17)test_amount_given_as_text()
-> assert final_balance(transactions) == 70
(Pdb) p transactions
[{'type': 'deposit', 'amount': 100}, {'type': 'withdrawal', 'amount': '30'}]

pdb zaczyna w funkcji, w której padł wyjątek, więc od razu widzisz '30' jako tekst. Polecenie up przenosi Cię o poziom wyżej, do testu, który tę funkcję wywołał, i pokazuje całe dane wejściowe. Nie używaj tu w bez argumentu: pytest dokłada do stosu dziesiątki własnych ramek i wynik jest nieczytelny.

Po zakończeniu pracy w pdb wpisz q, a pytest przerwie bieg testów. Po więcej o pisaniu testów w pytest zobacz artykuł o TDD i BDD w pytest i o testowaniu bazy danych.

Co zrobić, gdy zmienna ma nazwę taką jak polecenie pdb?

Jeśli w kodzie masz zmienną o nazwie c, n, s albo p, to wpisanie jej w (Pdb) wykona polecenie debuggera zamiast pokazać wartość. W przykładzie z breakpoint() zmienna nazywa się c:

(Pdb) p c
12
(Pdb) !c
12

Polecenie p c wypisuje wartość zmiennej, a wykrzyknik na początku wymusza wykonanie linii jako kodu Pythona, a nie polecenia debuggera. Samo c bez żadnego prefiksu wznowiłoby program, zamiast pokazać wartość. Najprościej: do podglądu zawsze używaj p.

Jak debugować Pythona w VS Code?

Potrzebujesz rozszerzenia Python Debugger (ms-python.debugpy), które instaluje się razem z rozszerzeniem Python. Najszybciej: kliknij strzałkę obok przycisku uruchamiania w edytorze i wybierz Python Debugger: Debug Python File. Albo naciśnij F5 po utworzeniu konfiguracji w pliku .vscode/launch.json:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Python Debugger: bieżący plik",
      "type": "debugpy",
      "request": "launch",
      "program": "${file}",
      "console": "integratedTerminal",
      "justMyCode": true
    }
  ]
}

Breakpoint ustawiasz, klikając na lewo od numeru linii. Po zatrzymaniu panele Variables, Watch i Call Stack pokazują to samo, co p, display i w w pdb. W Debug Console możesz wpisywać wyrażenia, które wykonają się w kontekście zatrzymanego programu.

VS Code ma dwa rodzaje breakpointów, które warto znać. Warunkowy ma wyrażenie albo licznik trafień (hit count), np. >5 zatrzymuje dopiero po piątym trafieniu. Logpoint wypisuje komunikat w Debug Console bez zatrzymywania programu i bez dopisywania print w kodzie. Drugą drogą jest debugpy.breakpoint() wpisane w kodzie.

Skróty edytora, które przyspieszają pracę w VS Code, opisuje artykuł o skrótach w VS Code.

Dlaczego VS Code nie zatrzymuje się na breakpoincie? Lista kontrolna

Najczęstsze powody, w kolejności od najprostszych:

  1. Program uruchomiono bez debugowania. Przycisk uruchamiania i Debug Python File to dwie różne rzeczy. Breakpointy działają tylko w trybie debugowania.
  2. Linia nie jest wykonywana. Warunek if jest fałszywy, funkcja nigdy nie jest wywołana albo skrypt kończy się wcześniej. Ustaw breakpoint wcześniej, na linii, która na pewno się wykona, i krokuj dalej.
  3. Wybrany jest zły interpreter Pythona. Debugger uruchamia kod innym Pythonem niż ten, z którego korzysta projekt, więc nie widzisz zależności z .venv. Sprawdź w pasku statusu, który interpreter jest wybrany.
  4. justMyCode jest włączone. Domyślnie debugger pomija kod bibliotek i zatrzymuje się tylko w Twoim. Jeśli breakpoint jest w kodzie biblioteki, ustaw w launch.json "justMyCode": false.
  5. Zmienna PYTHONBREAKPOINT=0 jest ustawiona w środowisku. Wtedy wywołania breakpoint() są ignorowane (patrz sekcja wyżej).
  6. Kod działa w innym procesie. Dotyczy serwerów z automatycznym przeładowaniem i kodu uruchamianego w podprocesach. Wtedy zamiast uruchamiać program z VS Code, możesz uruchomić go samodzielnie przez python -m debugpy --listen 5678 skrypt.py i dołączyć się konfiguracją typu attach na porcie 5678.
  7. Wybrano nie tę konfigurację. Sprawdź na pasku Run and Debug, która konfiguracja z launch.json jest wybrana, i czy jej program lub url wskazują właściwy plik.

Zacznij od punktów 1–3. Rozwiązują większość przypadków.

Najczęstsze błędy przy debugowaniu Pythona

  • Zostawione breakpoint() w kodzie. Na serwerze zatrzyma proces i będzie czekał na wejście z klawiatury, którego nikt nie wpisze.
  • q zamiast c. q kończy cały program, c tylko wznawia do następnego breakpointu.
  • Zgadywanie zamiast obserwacji. Zmieniasz kod „na próbę”, aż coś zadziała, zamiast sprawdzić stan w miejscu błędu.
  • Szukanie błędu w testowanej funkcji, gdy dane wejściowe są złe. Polecenie up w pytest --pdb pokaże, co faktycznie przekazał test.
  • Za późno postawiony breakpoint. Postawiony na linii, w której błąd już jest widoczny, pokazuje skutek, a nie przyczynę.

Podsumowanie

W Pythonie wystarczą trzy rzeczy: breakpoint() w kodzie, p do podglądu i n/s/c do krokowania. Do tego pytest --pdb, gdy test pada z wyjątkiem, i warunkowy breakpoint, gdy błąd jest w jednej iteracji ze stu. Gdy kod napisało AI, ten sam proces opisuje artykuł o debugowaniu kodu z AI. Jeśli dopiero zaczynasz, wróć do wprowadzenia do debuggera.

Konsultacja i warsztaty devmentor.pl

Masz pytania?

Partnerzy

Firmy, z którymi współpracujemy

To partnerzy odpowiedzialni za staże po naszych kursach. Organizują je dla najlepszych absolwentów.

Zobacz wszystkich partnerów →
  • VR Medical
  • Sophona
  • Robot Force