Debugging Highlights Summary
Every highlight bullet from the 11 pages in this section, gathered on one page and grouped by the page it came from.
- Most non-obvious Python bugs are boundary bugs - a boundary you assumed was enforced turned out to be permeable
- Each scenario in this section has its own tell-tale signature that narrows which boundary actually broke
- A symptom - a hang, a crash, a slow leak - is not a diagnosis; the same symptom maps to several distinct boundary failures
- Narrowing scope with evidence before forming a hypothesis is faster than reading code until something looks wrong
- Default arguments with mutable objects become shared state across all function calls
- Use None as sentinel then create fresh mutable inside to ensure state isolation per call
- Apply field default_factory dict to dataclass fields instead of mutable defaults
- Tests pass individually but fail together when mutable defaults leak state across runs
- Check if x is None not if x or [] to detect missing args since empty lists are falsy
- Immutable defaults like tuples None and strings are safe from cross call contamination
- Circular imports occur when module A loads B while B initializes and tries to import A
- Extract shared value types to a leaf module both sides import to fix structural cycles
- Use python -X importtime to diagnose circular import chains and startup order problems
- TYPE_CHECKING-only imports break cycles for static tools without runtime cost
- String annotations hide cycles without fixing architecture; extract types instead
- Move IO side effects to main/startup hooks to avoid worsening cycle debugging
- Event loops freeze when sync I/O runs inside async functions
- Use asyncio.sleep not time.sleep to avoid blocking the loop
- Offload blocking work with await asyncio.to_thread(sync_call)
- Reuse httpx.AsyncClient across requests to avoid socket exhaustion
- Acquire all locks in the same order to prevent task deadlock
- Set loop.slow_callback_duration to find blocking code in debug
- Use tracemalloc.start() and take_snapshot() to find memory leaks in long-running processes
- Unbounded module-level dicts retain every object forever - bound with LRU or OrderedDict
- lru_cache without maxsize grows unbounded - always set maxsize like 4096
- Asyncio tasks from create_task leak if not explicitly cancelled on shutdown
- Reference cycles with del complicate GC - use weakref or explicit close()
- Small per-request leaks become gigabytes in long-running servers via process reuse
- Open text files with explicit UTF-8 encoding to avoid locale-default codec mismatches
- Encode strings to bytes before binary concatenation to prevent TypeError from mixing types
- Use unicodedata.normalize with casefold for robust string comparison across Unicode forms
- Strings hold Unicode code points while bytes hold raw octets; encodings map between them
- Double encoding produces mojibake when UTF-8 bytes decode as Latin-1 then re-encode as UTF-8
- Chardet guessing silently corrupts data in production; fix upstream encoding first
- Use Decimal for money, float for science, Fraction for ratios
- Construct Decimal from strings to preserve precision exactly
- Compare floats with math.isclose() instead of == operator
- Pandas sums are non-associative, use Decimal or integer cents
- Quantize Decimal with ROUND_HALF_UP for deterministic money
- Display rounding mismatch: quantize at comparison boundary
- Virtual environments isolate packages; lockfiles pin transitive versions
- Binary wheels tie to Python ABI tags like cp314 vs cp313
- PYTHONPATH shadowing imports the wrong package version
- Editable installs symlink source; wrong cwd loads wrong code
- Global pip install pollutes base Python; use venv per project
- Optional extras must be installed explicitly in CI configs
- sum() skips NaN silently - use dropna before aggregating
- pd.to_numeric with errors=coerce turns bad values into NaN silently
- Unvalidated merge keys multiply rows - use validate=one_to_one to catch
- Polars lazy pipelines need null filters before sum
- fillna(0) on optional fields turns missing into zeros and inflates revenue
- CSV dtype inference guesses wrong on IDs and strings - specify dtype explicitly
- Set PYTHONBREAKPOINT=0 in production to disable breakpoint() calls
- Use pdb.pm() to inspect state after exceptions occur
- Choose ipdb for IPython tab completion and syntax highlighting
- debugpy lets your IDE inject breakpoints into running code without redeploy
- Use structured logging in production instead of breakpoint to avoid halting
- Apply faulthandler and tracemalloc to catch production hangs and memory leaks
- Use sentinel None instead of mutable default arguments
- Extract circular imports into dedicated types.py modules
- Replace blocking calls with async equivalents in handlers
- Use Decimal for monetary math instead of float arithmetic
- Specify encoding explicitly when reading all text files
- Validate pandas merges with one_to_one to catch errors
Revisado por Chris St. John·Última actualización: 31 jul 2026