Posts Tagged ‘PythonInternals’
[PyConUS2025] Or Else: Exploring Lesser-Known Control-Flow Constructs in Python
Lecturer
Amethyst Reese is a senior software engineer specializing in foundational infrastructure and developer tooling. Professional Python work began in 2010; subsequent roles have included production engineering at Meta and senior engineering at Astral on the Ruff linter. Reese maintains multiple open-source libraries under the omnilib organization and speaks regularly at Python conferences. Personal site: https://amethyst.cat; GitHub: amyreese.
Abstract
Amethyst Reese examines control-flow mechanisms that lie beyond the familiar if, for, and while constructs. The talk surveys the else clauses attached to try, for, and while statements, demonstrates how decorators and generators can be repurposed to invent new control structures, and illustrates the resulting techniques with a compact text-adventure engine built entirely from generator-based state machines. Throughout, the guiding criterion remains readability: syntactic novelty is justified only when it renders intent more obvious to future maintainers.
Fundamental Alternatives and the Versatile Else Clause
Control flow comprises any language feature that alters the sequential execution of statements. The elementary building blocks—conditionals, loops, and function calls—can express every higher-order pattern, yet Python supplies additional syntactic forms that make certain patterns more concise. List, set, and dictionary comprehensions are the most widely used; they collapse a for loop and optional filtering into a single expression. When the expression grows nested or multi-clause, however, the gain in compactness may be offset by a loss of transparency. Multi-line comprehensions can conceal cyclomatic complexity that would be visually apparent in an equivalent nested loop, leading maintainers to underestimate performance cost. Reese therefore urges developers to weigh not only runtime efficiency but also the cognitive load imposed on the next reader.
The else clause, ordinarily associated with if, appears in three additional contexts. Inside a try statement an else block executes only when no exception was raised, providing a natural location for success-path logic while keeping the try suite minimal. Unlike finally, a return inside the try suite bypasses else; critical cleanup must therefore remain in finally or be placed after the entire construct. In a for loop the else suite runs if and only if the iterator was exhausted without encountering a break—exactly the situation in which a search has failed to locate its target. The same semantics apply to while: else executes when the loop condition becomes false rather than when a break occurs. In each case the language supplies, free of charge, a Boolean flag that programmers would otherwise maintain manually. The resulting code is both shorter and more declarative.
Decorators, Generators, and Custom Control Structures
Decorators are themselves a control-flow device: the @ syntax is executed at definition time, replacing the original object with whatever the decorator returns. Most decorators wrap the original callable, inserting logging, timing, or authorization checks. Because the decorator body runs immediately, it can also perform side effects or even begin iteration. Reese exploits this property to reconstruct two control structures familiar from other languages. An “until” decorator repeatedly invokes its wrapped function until a supplied predicate becomes true, thereby inverting the sense of a while loop. A more elaborate “do” / “while” pair implements the classic do-while pattern: the body always executes at least once, after which the predicate is evaluated. The published do-while package on PyPI encapsulates the necessary bookkeeping, supporting both callables and truthy collections as termination conditions.
Generators supply a second, more powerful substrate. A function containing yield is suspended at each yield point and may later be resumed; values can be sent inward via the send method and exceptions injected via throw. These primitives enable cooperative multitasking and, more relevantly, explicit state machines. Reese constructs a minimal scheduler that treats each generator as a state. Yielding the name of another generator function effects a transition; the target generator resumes exactly where it previously left off. Shared mutable state can be passed among the generators, allowing them to coordinate. The technique is demonstrated by a text-adventure game whose rooms are individual generator functions. Player commands are read inside a room, game state is updated, and a different room function is yielded to move the player. The entire engine occupies fewer than thirty lines; the complete adventure, including all rooms and logic, remains under two hundred lines.
The closing counsel is conservative. Novel control-flow constructs should be introduced only when they render the author’s intention clearer than the equivalent expansion into elementary forms. “Clear is better than clever.” Decorators that invert loop conditions or generators that encode state machines can satisfy that test, yet they also risk becoming opaque to colleagues unfamiliar with the idiom. Compassion for future readers—including one’s future self—remains the ultimate design constraint.