Lesson 4 / 25
A Loop with Every Guard
Combine step, token and time limits in one reusable budget object.
One object owns the limits
Scattering if checks through the loop makes limits easy to forget. A small Budget object tracks steps, tokens and elapsed time, and answers one question: "may we continue, and if not, why?" The loop asks it once per turn.
A Budget class
This ran as shown. Charging 3,000, 4,000 and 4,000 tokens trips the 10,000-token limit on the third step, and reason() says why.
class Budget:
def __init__(self, max_steps, max_tokens):
self.max_steps, self.max_tokens = max_steps, max_tokens
self.steps = self.tokens = 0
def charge(self, tokens):
self.steps += 1
self.tokens += tokens
def reason(self):
if self.steps >= self.max_steps: return "step limit"
if self.tokens >= self.max_tokens: return "token budget"
return None
b = Budget(5, 10_000)
for used in (3000, 4000, 4000):
b.charge(used)
print(b.steps, b.tokens, b.reason())
Output:
1 3000 None 2 7000 None 3 11000 token budget
Return a reason, not just a boolean
"Stopped" is useless in a log. "Stopped: token budget at step 3" tells you what to fix. Make every stop carry a reason string.
Quick check: Why centralise limits in one Budget object?
- Scattered checks are easy to forget or apply inconsistently
- Python requires classes
- It makes the model smarter
- It removes the need for tests
Answer
Scattered checks are easy to forget or apply inconsistently — One owner of the limits keeps checks consistent and the stop reason easy to report.