breakpoint() Function Complexity¶
The breakpoint() function calls sys.breakpointhook(), passing its arguments straight through,
and returns what the hook returns. Its own work is O(1); what a call costs is the hook's. The
default hook reads the PYTHONBREAKPOINT environment variable on every call and either returns at
once, calls the function the variable names, or enters pdb.
d is frames on the stack at the call and c is files in the linecache cache. A function named
by PYTHONBREAKPOINT or installed as the hook costs whatever it does, added on top; importing its
module the first time is a one-time cost the bounds leave out.
Complexity Reference¶
breakpoint and sys.breakpointhook¶
| Operation | Time | Space | Notes |
|---|---|---|---|
breakpoint(*args, **kws) |
O(1) plus the hook | O(1) plus the hook | Calls sys.breakpointhook(*args, **kws) and returns its result; raises the builtins.breakpoint audit event first |
sys.breakpointhook = hook |
O(1) | O(1) | breakpoint() then calls hook, and PYTHONBREAKPOINT is not read |
sys.__breakpointhook__ |
O(1) | O(1) | The default hook, kept so a replacement can be undone |
The default hook¶
| Operation | Time | Space | Notes |
|---|---|---|---|
PYTHONBREAKPOINT unset or empty |
O(c + d) | O(c + d) | Calls pdb.set_trace() and waits for a command; the pdb page prices it, including the Pdb it builds |
PYTHONBREAKPOINT=0 |
O(1) | O(1) | Returns None without importing anything |
PYTHONBREAKPOINT=module.function |
O(1) plus the function | O(1) plus the function | Imports module and returns function(*args, **kws); a name with no dot is a builtin, such as int |
PYTHONBREAKPOINT naming a missing module or attribute |
O(1) | O(1) | Emits a RuntimeWarning and returns None |
Replacing the Hook¶
Assigning sys.breakpointhook routes every breakpoint() call to the new function, arguments
and return value included. PYTHONBREAKPOINT is no longer consulted, so a test can intercept
breakpoints whatever the environment says.
import sys
calls = []
def record(*args, **kws):
calls.append((args, kws))
return 'recorded'
previous = sys.breakpointhook
sys.breakpointhook = record
try:
result = breakpoint('here', depth=3) # O(1) plus record()
finally:
sys.breakpointhook = previous
assert result == 'recorded'
assert calls == [(('here',), {'depth': 3})]
Choosing a Hook With PYTHONBREAKPOINT¶
The default hook reads PYTHONBREAKPOINT each time it is called, so changing os.environ takes
effect on the next breakpoint(). 0 makes every call an O(1) no-op that returns None.
import os
os.environ['PYTHONBREAKPOINT'] = '0'
assert breakpoint() is None # O(1): no debugger, no import
Any other value names a callable by its dotted path. The module part is imported, and the
callable gets breakpoint()'s arguments and supplies its return value.
import os
os.environ['PYTHONBREAKPOINT'] = 'json.dumps'
assert breakpoint([1, 2]) == '[1, 2]' # O(1) plus json.dumps([1, 2])
os.environ['PYTHONBREAKPOINT'] = 'int'
assert breakpoint('42') == 42 # no dot: the builtin int
A module that does not exist, or one without that attribute, is not an error: the call warns and does nothing.
import os
import warnings
os.environ['PYTHONBREAKPOINT'] = 'no_such_module.hook'
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter('always')
assert breakpoint() is None # O(1): warns, no debugger
assert caught[0].category is RuntimeWarning
assert 'no_such_module.hook' in str(caught[0].message)
python -E and python -I ignore PYTHONBREAKPOINT, as they do the other PYTHON* variables,
so under either a breakpoint() left in the code enters pdb even when the variable is 0.
Entering pdb¶
With PYTHONBREAKPOINT unset, breakpoint() is pdb.set_trace() at the call site: entering
costs O(c + d), and the stop waits for input. After continue
the program runs under the debugger's trace hook, or untraced if no breakpoints are set; the
pdb page prices both, and how they differ between the 'settrace' and
'monitoring' backends.
Performance Best Practices¶
✅ Do:
- Set
PYTHONBREAKPOINT=0where a straybreakpoint()must not stop the program: each call becomes O(1) and imports nothing - Replace
sys.breakpointhookto intercept breakpoints in tests, saving the previous hook to restore;sys.__breakpointhook__is the default continuewith no breakpoints set when you are done, so the rest of the program runs untraced
❌ Avoid:
- Relying on
PYTHONBREAKPOINT=0underpython -Eor-I, which ignore it - Passing positional arguments to
breakpoint()whilePYTHONBREAKPOINTis unset:pdb.set_trace()accepts none and raisesTypeError
Version Notes¶
- Python 3.14+: the default hook's
pdb.set_trace()reuses the lastPdbwhoseset_trace()ran, and otherwise builds one on the'monitoring'backend; earlier releases build a newPdbon every call