Python skill practice
How do you approach this?
Python Debugging Practice for Developers
Published · Updated
Published by Unrust. Scoring and editorial method
Quick answer
Debug Python by reproducing one failure with the smallest useful input and inspecting the actual objects, exceptions, and control flow involved. Watch for mutable defaults, aliasing, broad exception handlers, and iteration over unexpected data because each can make an explanation sound right while missing the cause. Preserve the original reproduction and test one hypothesis at a time before changing a larger system.
Original example
Inspect a mutable default before assuming each call is isolated
def add_tag(tag, tags=[]):
tags.append(tag)
return tagsThis original Python example is a compact prompt for evidence gathering: the default list is created once and then shared across calls, so a later result can reflect earlier state. The next step is to reproduce two calls and decide what ownership contract the function should provide, rather than applying a remembered fix without checking its callers.
Inspect object lifetime and mutation
A list, dictionary, or default argument can survive longer or be shared more widely than a function's local names suggest. Use ids, focused assertions, or a debugger to see whether an update changed the same object across calls before replacing the logic that happens to expose the mutation.
Keep exception evidence visible
A broad except clause can turn a useful error into a vague fallback, making later diagnosis harder. Capture the exception type, input, and relevant state first, then decide whether the caller should handle a known case, receive an explicit failure, or let an unexpected error surface for investigation.
Check a concrete outcome
Use the original example with this input. These are local teaching fixtures, checked against the displayed snippet; they do not call external services.
Both returned names refer to the same default list, including the later mutation. Use a None default and allocate a list inside the function when each call should own its collection.
| Expression after the example | Observed result |
|---|---|
| (lambda first, second: {"first": first, "second": second, "shared": first is second})(add_tag("a"), add_tag("b")) | {"first": ["a", "b"], "second": ["a", "b"], "shared": True} |
Checklist
- Which Python objects are shared or retained across calls?
- What exception type and input support the current diagnosis?
- Does a fallback hide evidence that callers need to see?
Practice loop
- 01Reduce a Python failure to the smallest input and print or assert the relevant object state.
- 02Check whether a list, dictionary, or default value is shared across calls unexpectedly.
- 03Replace one broad diagnostic guess with a test that distinguishes exception paths or data shapes.
Limits of this page
A compact Python reproduction may not include process boundaries, threads, package versions, or production data history. A short debugging session can identify a useful topic to practice, but it cannot explain why a real failure was difficult or measure incident readiness.
Source context
Published by Unrust as practical teaching material using public language documentation and original examples. See the scoring and editorial method for scope, checking and limitations.
Check your own starting point
One diagnostic session is a snapshot, not causal proof of why a result occurred. It can help you choose a focused next practice step without making a broader claim about your ability.
Take the free diagnosticTake the read in Python →Same six skills, side by side on your dashboard.