[{"data":1,"prerenderedAt":516},["ShallowReactive",2],{"page-\u002Fsystematic-debugging-performance-profiling\u002Finteractive-debugging-with-pdb-and-ipdb\u002Fsetting-conditional-breakpoints-in-pdb\u002F":3},{"id":4,"title":5,"body":6,"description":482,"extension":483,"meta":484,"navigation":133,"path":512,"seo":513,"stem":514,"__hash__":515},"content\u002Fsystematic-debugging-performance-profiling\u002Finteractive-debugging-with-pdb-and-ipdb\u002Fsetting-conditional-breakpoints-in-pdb\u002Findex.md","Setting Conditional Breakpoints in pdb",{"type":7,"value":8,"toc":475},"minimark",[9,23,28,68,72,81,147,194,197,221,227,260,270,306,317,321,343,347,419,423,436,451,465,471],[10,11,12,13,17,18,22],"p",{},"You are stepping through a loop that processes 50,000 records and the bug only shows on one of them. A plain breakpoint stops on every iteration, so you hammer ",[14,15,16],"code",{},"continue"," hundreds of times before reaching the interesting one — or give up. A conditional breakpoint stops ",[19,20,21],"em",{},"only"," when a predicate is true, dropping you into the prompt on the exact iteration where the invariant breaks.",[24,25,27],"h2",{"id":26},"prerequisites","Prerequisites",[29,30,31,59],"ul",{},[32,33,34,38,39,42,43,46,47,50,51,54,55,58],"li",{},[35,36,37],"strong",{},"Python 3.7+"," for ",[14,40,41],{},"breakpoint()","; the ",[14,44,45],{},"b",", ",[14,48,49],{},"tbreak",", and ",[14,52,53],{},"condition"," commands work in every ",[14,56,57],{},"pdb"," version.",[32,60,61,62,67],{},"Familiarity with entering the debugger and the basic command loop from ",[63,64,66],"a",{"href":65},"\u002Fsystematic-debugging-performance-profiling\u002Finteractive-debugging-with-pdb-and-ipdb\u002F","interactive debugging with pdb and ipdb",".",[24,69,71],{"id":70},"solution","Solution",[10,73,74,75,77,78,80],{},"There are two ways to make ",[14,76,57],{}," stop conditionally: a line breakpoint with an inline condition, and a guarded ",[14,79,41],{}," call in source. Start with the command form, which requires no source edits.",[82,83,88],"pre",{"className":84,"code":85,"language":86,"meta":87,"style":87},"language-python shiki shiki-themes github-light github-dark","# orders.py\ndef process(orders):\n    total = 0\n    for i, qty in enumerate(orders):\n        total += qty          # we suspect a negative qty corrupts the total\n    return total\n\nif __name__ == \"__main__\":\n    process([5, 3, 8, -2, 9, 4])\n","python","",[14,89,90,98,104,110,116,122,128,135,141],{"__ignoreMap":87},[91,92,95],"span",{"class":93,"line":94},"line",1,[91,96,97],{},"# orders.py\n",[91,99,101],{"class":93,"line":100},2,[91,102,103],{},"def process(orders):\n",[91,105,107],{"class":93,"line":106},3,[91,108,109],{},"    total = 0\n",[91,111,113],{"class":93,"line":112},4,[91,114,115],{},"    for i, qty in enumerate(orders):\n",[91,117,119],{"class":93,"line":118},5,[91,120,121],{},"        total += qty          # we suspect a negative qty corrupts the total\n",[91,123,125],{"class":93,"line":124},6,[91,126,127],{},"    return total\n",[91,129,131],{"class":93,"line":130},7,[91,132,134],{"emptyLinePlaceholder":133},true,"\n",[91,136,138],{"class":93,"line":137},8,[91,139,140],{},"if __name__ == \"__main__\":\n",[91,142,144],{"class":93,"line":143},9,[91,145,146],{},"    process([5, 3, 8, -2, 9, 4])\n",[82,148,152],{"className":149,"code":150,"language":151,"meta":87,"style":87},"language-console shiki shiki-themes github-light github-dark","$ python -m pdb orders.py\n(Pdb) b orders.py:5, qty \u003C 0     # break at line 5 ONLY when qty is negative\nBreakpoint 1 at orders.py:5\n(Pdb) c                          # run; pdb skips every iteration until the predicate holds\n> orders.py(5)process()\n-> total += qty\n(Pdb) p i, qty                   # we land exactly on the bad iteration\n(3, -2)\n","console",[14,153,154,159,164,169,174,179,184,189],{"__ignoreMap":87},[91,155,156],{"class":93,"line":94},[91,157,158],{},"$ python -m pdb orders.py\n",[91,160,161],{"class":93,"line":100},[91,162,163],{},"(Pdb) b orders.py:5, qty \u003C 0     # break at line 5 ONLY when qty is negative\n",[91,165,166],{"class":93,"line":106},[91,167,168],{},"Breakpoint 1 at orders.py:5\n",[91,170,171],{"class":93,"line":112},[91,172,173],{},"(Pdb) c                          # run; pdb skips every iteration until the predicate holds\n",[91,175,176],{"class":93,"line":118},[91,177,178],{},"> orders.py(5)process()\n",[91,180,181],{"class":93,"line":124},[91,182,183],{},"-> total += qty\n",[91,185,186],{"class":93,"line":130},[91,187,188],{},"(Pdb) p i, qty                   # we land exactly on the bad iteration\n",[91,190,191],{"class":93,"line":137},[91,192,193],{},"(3, -2)\n",[10,195,196],{},"The condition is any expression valid in the target frame; pdb evaluates it on every hit and stops only when it is truthy. To attach a condition to an existing breakpoint, or change one, reference the breakpoint by its number:",[82,198,200],{"className":149,"code":199,"language":151,"meta":87,"style":87},"(Pdb) b orders.py:5             # unconditional breakpoint, gets number 1\nBreakpoint 1 at orders.py:5\n(Pdb) condition 1 qty \u003C 0       # retrofit the predicate onto breakpoint 1\n(Pdb) condition 1               # omit the expression to clear it again\n",[14,201,202,207,211,216],{"__ignoreMap":87},[91,203,204],{"class":93,"line":94},[91,205,206],{},"(Pdb) b orders.py:5             # unconditional breakpoint, gets number 1\n",[91,208,209],{"class":93,"line":100},[91,210,168],{},[91,212,213],{"class":93,"line":106},[91,214,215],{},"(Pdb) condition 1 qty \u003C 0       # retrofit the predicate onto breakpoint 1\n",[91,217,218],{"class":93,"line":112},[91,219,220],{},"(Pdb) condition 1               # omit the expression to clear it again\n",[10,222,223,224,226],{},"For a breakpoint you only ever want to hit once — the common case inside a hot loop — use ",[14,225,49],{},". It fires a single time and removes itself, so there is no leftover breakpoint to disable afterward:",[82,228,230],{"className":149,"code":229,"language":151,"meta":87,"style":87},"(Pdb) tbreak orders.py:5, qty \u003C 0    # one-shot: auto-removed after the first hit\nBreakpoint 2 at orders.py:5\n(Pdb) c\n> orders.py(5)process()\n-> total += qty\n(Pdb) c                              # continues to the end; breakpoint is already gone\n",[14,231,232,237,242,247,251,255],{"__ignoreMap":87},[91,233,234],{"class":93,"line":94},[91,235,236],{},"(Pdb) tbreak orders.py:5, qty \u003C 0    # one-shot: auto-removed after the first hit\n",[91,238,239],{"class":93,"line":100},[91,240,241],{},"Breakpoint 2 at orders.py:5\n",[91,243,244],{"class":93,"line":106},[91,245,246],{},"(Pdb) c\n",[91,248,249],{"class":93,"line":112},[91,250,178],{},[91,252,253],{"class":93,"line":118},[91,254,183],{},[91,256,257],{"class":93,"line":124},[91,258,259],{},"(Pdb) c                              # continues to the end; breakpoint is already gone\n",[10,261,262,263,265,266,269],{},"When you would rather express the predicate in source — for example because the condition is expensive or spans multiple statements — guard a ",[14,264,41],{}," call with an ",[14,267,268],{},"if",":",[82,271,273],{"className":84,"code":272,"language":86,"meta":87,"style":87},"def process(orders):\n    total = 0\n    for i, qty in enumerate(orders):\n        if qty \u003C 0:               # only enter the debugger on the offending value\n            breakpoint()\n        total += qty\n    return total\n",[14,274,275,279,283,287,292,297,302],{"__ignoreMap":87},[91,276,277],{"class":93,"line":94},[91,278,103],{},[91,280,281],{"class":93,"line":100},[91,282,109],{},[91,284,285],{"class":93,"line":106},[91,286,115],{},[91,288,289],{"class":93,"line":112},[91,290,291],{},"        if qty \u003C 0:               # only enter the debugger on the offending value\n",[91,293,294],{"class":93,"line":118},[91,295,296],{},"            breakpoint()\n",[91,298,299],{"class":93,"line":124},[91,300,301],{},"        total += qty\n",[91,303,304],{"class":93,"line":130},[91,305,127],{},[10,307,308,309,312,313,316],{},"You can also raise the hit count with ",[14,310,311],{},"ignore",": ",[14,314,315],{},"ignore 1 100"," tells pdb to skip the next 100 hits of breakpoint 1 before honouring it — useful when you know the bug is \"around iteration 100\" but cannot express it as a value predicate.",[24,318,320],{"id":319},"why-this-works","Why this works",[10,322,323,325,326,329,330,332,333,335,336,339,340,342],{},[14,324,57],{}," stores conditions on the breakpoint object and evaluates them inside the paused frame's namespace via ",[14,327,328],{},"eval",", so any in-scope name or expression is fair game. Because evaluation happens on every hit, a condition is functionally identical to a guarded ",[14,331,41],{}," — the command form just keeps the predicate out of your source. ",[14,334,49],{}," is a normal breakpoint with a ",[14,337,338],{},"temporary=True"," flag that pdb clears on first fire, and ",[14,341,311],{}," decrements a counter before the condition is even checked.",[24,344,346],{"id":345},"edge-cases-and-failure-modes","Edge cases and failure modes",[29,348,349,371,381,395,407],{},[32,350,351,354,355,358,359,362,363,366,367,370],{},[35,352,353],{},"A condition that raises"," (e.g. ",[14,356,357],{},"qty \u003C 0"," when ",[14,360,361],{},"qty"," is sometimes ",[14,364,365],{},"None",") makes pdb treat the breakpoint as hit and stops anyway — guard with ",[14,368,369],{},"isinstance"," checks inside the expression if the variable's type varies.",[32,372,373,376,377,380],{},[35,374,375],{},"Conditions evaluate in the target frame, not where you typed them","; a name that exists in your prompt frame but not the breakpoint's frame raises ",[14,378,379],{},"NameError"," on every hit.",[32,382,383,386,387,390,391,394],{},[35,384,385],{},"Side-effecting conditions run on every hit"," — never put a mutation or a ",[14,388,389],{},"print"," in a condition; use ",[14,392,393],{},"commands"," for that instead.",[32,396,397,402,403,406],{},[35,398,399,401],{},[14,400,49],{}," with a condition"," still consumes its single life on the first time the ",[19,404,405],{},"condition is true",", not the first time the line is reached.",[32,408,409,412,413,415,416,418],{},[35,410,411],{},"Conditional breakpoints add per-hit overhead","; on a million-iteration loop the eval cost is noticeable, so prefer a guarded ",[14,414,41],{}," or ",[14,417,311],{}," count when the predicate is hot.",[24,420,422],{"id":421},"frequently-asked-questions","Frequently Asked Questions",[10,424,425,428,429,432,433,435],{},[35,426,427],{},"How do I make pdb break only when a variable has a specific value?","\nSet the breakpoint with a condition: ",[14,430,431],{},"b orders.py:42, qty \u003C 0",". pdb evaluates the expression in the target frame on every hit and only stops when it is truthy, so the prompt opens on the iteration where ",[14,434,361],{}," goes negative.",[10,437,438,441,444,445,447,448,450],{},[35,439,440],{},"What is the difference between break and tbreak in pdb?",[14,442,443],{},"break"," (",[14,446,45],{},") sets a persistent breakpoint that stops every time the line is reached. ",[14,449,49],{}," sets a temporary breakpoint that is removed automatically the first time it fires, which is ideal for stopping once inside a hot loop.",[10,452,453,456,457,460,461,464],{},[35,454,455],{},"Can I add a condition to a breakpoint I already set?","\nYes. Use ",[14,458,459],{},"condition bpnumber expression"," to attach or change the condition on an existing breakpoint by its number, or ",[14,462,463],{},"condition bpnumber"," with no expression to clear it and make the breakpoint unconditional again.",[10,466,467,468],{},"← Back to ",[63,469,470],{"href":65},"Interactive Debugging with pdb and ipdb",[472,473,474],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":87,"searchDepth":100,"depth":100,"links":476},[477,478,479,480,481],{"id":26,"depth":100,"text":27},{"id":70,"depth":100,"text":71},{"id":319,"depth":100,"text":320},{"id":345,"depth":100,"text":346},{"id":421,"depth":100,"text":422},"Stop pdb only when it matters: set conditional breakpoints with b file:line, condition, tbreak, and breakpoint() guards so the prompt opens on the exact loop iteration.","md",{"slug":485,"type":486,"breadcrumb":487,"datePublished":488,"dateModified":488,"faq":489,"howto":496},"setting-conditional-breakpoints-in-pdb","long_tail","Conditional Breakpoints","2026-06-18",[490,492,494],{"q":427,"a":491},"Set the breakpoint with a condition: b orders.py:42, qty \u003C 0. pdb evaluates the expression in the target frame on every hit and only stops when it is truthy, so the prompt opens on the iteration where qty goes negative.",{"q":440,"a":493},"break (b) sets a persistent breakpoint that stops every time the line is reached. tbreak sets a temporary breakpoint that is removed automatically the first time it fires, which is ideal for stopping once inside a hot loop.",{"q":455,"a":495},"Yes. Use condition bpnumber expression to attach or change the condition on an existing breakpoint by its number, or condition bpnumber with no expression to clear it and make the breakpoint unconditional again.",{"name":497,"description":498,"steps":499},"How to set conditional breakpoints in pdb","Break only when a predicate is true so the debugger stops on the precise iteration that triggers a defect.",[500,503,506,509],{"name":501,"text":502},"Set a line breakpoint with a condition","Run b file:line, expression so pdb stops only when the expression evaluates truthy in the target frame.",{"name":504,"text":505},"Attach or change conditions on existing breakpoints","Use condition bpnumber expression to add a predicate to a breakpoint, or clear it by omitting the expression.",{"name":507,"text":508},"Use tbreak for a one-shot stop","Set a temporary breakpoint that auto-removes after the first hit to avoid re-triggering inside a loop.",{"name":510,"text":511},"Guard breakpoint() inline for tight loops","Wrap breakpoint() in an if predicate so the call only fires on the iteration of interest.","\u002Fsystematic-debugging-performance-profiling\u002Finteractive-debugging-with-pdb-and-ipdb\u002Fsetting-conditional-breakpoints-in-pdb",{"title":5,"description":482},"systematic-debugging-performance-profiling\u002Finteractive-debugging-with-pdb-and-ipdb\u002Fsetting-conditional-breakpoints-in-pdb\u002Findex","iH0KybYQ0tDLpzqf5EExHz7xN2yndhLMOOYrhJQvBd0",1781793487406]