3 Control Flow

A practical guide to Python control flow, from Boolean conditions and branching to loops, iteration, and reliable loop-control techniques.

The role of control flow

Control flow determines the order in which Python statements run. It lets a program choose among alternatives, repeat operations, and stop or skip work when appropriate.

Python identifies blocks by indentation. Statements belonging to an if, while, or for block must be indented consistently; incorrect indentation changes the structure of the program or causes an error.

A useful way to think about control flow is as three related questions:

  • Which condition is true?

  • Which block should run?

  • Should execution repeat, skip, or stop?

The main tools for answering these questions are Boolean logic, conditional statements, loops, and loop-control statements.

Takeaway: Control flow makes decisions and repetition explicit, and indentation shows which statements belong to each block.

Boolean logic and comparisons

A is either True or False. Comparisons such as age >= 18 or response == "yes" produce Boolean results. Python provides three main Boolean operators:

  • and is true when both operands are true.

  • or is true when at least one operand is true.

  • not reverses a truth value.

Python uses . For and, Python stops when the left operand is false because the whole result cannot become true. For or, Python stops when the left operand is true because the whole result is already determined. For example, items and items[0] == "ready" does not attempt to access the first item when items is empty.

A condition can test any object, not only an explicit Boolean. A behaves like True, while a behaves like False. Common falsy values include False, None, numeric zero, and empty strings, lists, tuples, dictionaries, sets, and ranges. Most other objects are truthy.

This makes a direct collection test clear and idiomatic: if names: checks whether names is nonempty. It is often preferable to explicitly comparing its length with zero.

Boolean operators can return one of their operands rather than the literal values True or False. Use bool(value) when an explicit Boolean conversion is needed.

Comparisons include <, <=, >, >=, ==, and !=. Use == for equality of values. uses is or is not and is primarily appropriate for singleton objects such as None; do not normally use is to compare strings or numbers.

Python also supports chained comparisons. The condition 0 <= score <= 100 expresses that score is within the inclusive range from zero through one hundred, and the middle expression is evaluated only once. Comparisons have higher precedence than and, or, and not, although parentheses can make complex conditions easier to read.

Takeaway: Build conditions from comparisons and Boolean operators, rely on truth-value testing for ordinary objects, and use deliberately.

Choosing between alternatives

An if statement runs a block only when its condition is truthy. An else block handles the alternative case, and one or more elif clauses allow a sequence of mutually exclusive choices.

Python evaluates an if statement from top to bottom and executes the first matching branch. Once a branch runs, later elif and else blocks are skipped. An else clause is optional.

For example, a grading decision can test thresholds in descending order:

  • If the score is at least ninety, assign A.

  • Otherwise, if it is at least eighty, assign B.

  • Otherwise, if it is at least seventy, assign C.

  • Otherwise, assign D.

The order matters: a broad condition placed too early can prevent a later, more specific condition from ever running.

A conditional can be nested inside another conditional. For instance, a program might first check whether a person is an adult and then check whether that person has a ticket. Nested decisions are valid, but deep nesting can become difficult to read. Combine related conditions with and, use early exits, or move complicated logic into a function when that produces a clearer design.

Validation should happen before dependent processing. A condition such as text.isdigit() and int(text) > 0 checks that the text contains digits before converting it to an integer. Because and short-circuits, the conversion is attempted only when the first test succeeds.

Takeaway: Put mutually exclusive branches in the correct order, validate prerequisites before using them, and simplify deeply nested decisions when possible.

Repeating work with loops

A repeats its body while its condition remains true. Python checks the condition before every iteration, so an initially false condition causes zero iterations.

A loop must make progress toward termination. For example, a counter can move downward until it reaches zero, or a number can grow until it exceeds a limit. If the condition never becomes false, the loop may run forever.

Use a when the number of repetitions is not known in advance and depends on changing state. A command prompt that continues until the user enters quit is a typical example.

A is usually better when the program should process each item in an . An can provide strings, lists, tuples, dictionaries, sets, or ranges. Iterating directly over a collection is generally clearer than manually managing an index.

Use enumerate() when both the position and the item are needed. For example, iterating over enumerate(names) can provide an index and a name together without separately tracking a counter.

The produces an sequence of integers. Its ending value is exclusive:

  • range(5) produces zero through four.

  • range(2, 6) produces two through five.

  • range(0, 10, 2) produces the even values from zero through eight.

  • range(5, 0, -1) produces five through one.

The general forms are range(stop), range(start, stop), and range(start, stop, step). A positive step requires the stopping value to be greater than the starting value, while a negative step requires it to be less. A step of zero raises an error. The range represents the sequence without creating a complete list in memory, which makes it efficient for iteration.

Choose a for condition-controlled repetition, a for item-oriented traversal, and range() for numeric sequences or positions. For ordinary collection traversal, iterate over the collection itself rather than using range(len(collection)) unless the positions are genuinely required.

Takeaway: Match the loop to the task: changing condition for while, items for for, and numeric progression for range().

Controlling and simplifying loops

The immediately ends the innermost enclosing loop. It is useful when a desired item has been found or when an early terminating condition has been discovered. In a nested-loop structure, break exits only the innermost loop that contains it.

The skips the rest of the current iteration and proceeds to the next one. It is useful when certain items should be ignored while the loop continues processing other items.

In a while loop, make sure any required counter or state update occurs before continue. Otherwise, the condition may never change and the loop may not terminate.

A practical loop design often follows this sequence:

  1. Establish the initial state.

  2. Check the loop condition or obtain the next item.

  3. Perform the work for the current iteration.

  4. Update the state when using a while loop.

  5. Use break for an early exit or continue to skip the remainder of an iteration.

  6. Confirm that normal execution can eventually reach termination.

Avoid unnecessary nesting. Combine compatible conditions, use early exits, or divide complex logic into functions. These choices make the possible paths through a program easier to understand and test.

Takeaway: Use break to stop, continue to skip, and explicit progress or exhaustion to guarantee that loops terminate.