4 Control Flow and Logic

A progressive guide to Python control flow, explaining sequence, conditionals, Boolean logic, loops, nesting, tracing, and reliable debugging practices.

The Foundations of Control Flow

Control flow is the order in which a program’s instructions execute. By default, statements run from top to bottom, but control-flow structures can select between alternatives, repeat instructions, or combine these behaviors. This allows an algorithm to respond to data rather than perform the same fixed every time.

A executes statements in order, once each. For example, a program can assign a price, assign a quantity, calculate a total, and then display the result. If the price is 1212, the quantity is 33, and the calculation is 12×312 \times 3, the displayed total is 3636. If a variable xx is updated from 55 to 77, a later statement uses the new value 77. The meaning of a program therefore depends on both the instructions it contains and their execution order.

The main control-flow patterns build on this default:

  • Selection chooses among alternatives.

  • repeats a process.

  • Nesting places one control structure inside another.

  • follows the actual execution path.

Takeaway: Execution order matters, and control-flow structures determine which instructions run, how often they run, and when they stop.

Selection with Conditionals

A chooses a branch based on a condition. Python tests if conditions from top to bottom. The first true branch runs, and the remaining branches are skipped. An elif branch supplies another condition, while an else branch handles the case in which no earlier condition is true.

Common comparisons include equality ====, inequality !=!=, less than <<, greater than >>, less than or equal to ≤\leq, and greater than or equal to ≥\geq. Assignment == stores a value; it is different from the equality test ====. In Python code, these concepts appear through operators such as =, ==, and >=.

For example, a grading decision can test whether a score is at least 9090, then at least 8080, and then at least 7070. A score of 7878 fails the first two tests, passes the third test, and receives the corresponding grade.

Python uses indentation to show which statements belong to each branch. Conditions should be ordered deliberately, especially when several ranges overlap. Test both the true and false outcomes, including boundary values such as the exact threshold.

Takeaway: A selects one execution path, so branch order, comparison choice, indentation, and boundary handling all matter.

Logic and Safe Conditions

A value is either True or False. expressions combine comparisons and control decisions.

  • and is true only when both expressions are true.

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

  • not reverses a value.

Parentheses make compound conditions easier to read. For example, a safety decision can be written as (temperature<0)or(snowingandroads_icy)(temperature < 0) \mathbin{\text{or}} (snowing \mathbin{\text{and}} roads\_icy), where the first alternative is true when the temperature is below zero and the second requires both snowfall and icy roads.

can prevent unnecessary or unsafe work. In a condition such as denominator≠0andnumerator÷denominator>1denominator \ne 0 \mathbin{\text{and}} numerator \div denominator > 1, the division is attempted only if the denominator is not zero. If the first part is false, the and expression is already known to be false. Similarly, an or expression may stop after a true first part.

Different languages use different notation, such as &&\&\&, ∣∣||, and !!, but the logical ideas are the same. Some languages, including Python and JavaScript, also allow certain non- values to behave like false in conditions; an empty collection and zero are common examples.

Takeaway: Build complex decisions from clear expressions, use parentheses when grouping may be unclear, and use short-circuit behavior to guard operations when appropriate.

with Loops

repeats a block of statements. Use a for loop when processing each item in a or a known range. In Python, range includes its starting value but excludes its ending value: range(1, 5) produces 11, 22, 33, and 44.

A loop can maintain an accumulator. Starting with 00 and adding each value from 11 through 55 produces the final total 1515. The accumulator is updated once per . This pattern is useful for sums, counts, products, and other running results.

Use a while loop when repetition should as long as a condition remains true. The condition is tested before each , so the loop needs an initial state, a condition, and an update that moves toward termination. If the update never makes the condition false, the result is an .

A statement ends the nearest loop immediately. A statement skips the rest of the current and starts the next one. For example, a loop can stop before printing a particular value with , or skip even values with . Use these statements carefully because excessive early exits can make a program harder to understand.

Takeaway: Choose for for - or count-oriented repetition and while for condition-oriented repetition; always make the stopping behavior explicit.

Nesting and Execution Cost

A contains one control structure inside another. A inside a loop is evaluated once per loop . In nested loops, the inner loop completes all of its iterations for each of the outer loop.

If two nested loops each run approximately nn times, the inner statement may execute approximately n×n=n2n \times n = n^2 times. This makes nested loops useful for grids, tables, and comparing every item in one collection with every item in another, while also increasing the amount of work.

Nesting can sometimes be replaced with a compound condition. For example, checking that a username is not empty and a password is not empty can be written as one condition using and, rather than as two deeply nested conditionals. Clear indentation is essential in either form.

When nested code, follow the outer structure first. For each outer-loop , complete every inner-loop before returning to the outer loop.

Takeaway: Trace nested structures from the outside inward, keep indentation consistent, and simplify nesting when a direct expression communicates the same decision.

, Testing, and Debugging

follows execution one statement at a time. A reliable trace records the initial values, assignments, condition results, loop variables, and output in the order they occur.

Use this process:

  1. Write down the initial value of every relevant variable.

  2. Read one executable statement at a time.

  3. Record each assignment immediately.

  4. Evaluate every condition as True or False.

  5. Follow only the selected branch.

  6. For each loop , record the loop variable and the values changed by the body.

  7. Record output when it occurs.

For a loop that adds only even numbers from 11 through 44, the running total begins at 00, remains 00 after the first odd value, becomes 22 after adding 22, remains unchanged at 22 after the next odd value, and ends at 66 after adding 44.

When designing or debugging, check zero items, empty input, the first value, the last value, and values exactly on a boundary. Common errors include confusing assignment with comparison, forgetting a while update, using incorrect indentation, ordering conditions incorrectly, and misunderstanding the excluded endpoint of range.

A small hand trace can reveal incorrect conditions, updates, boundaries, and branch choices before program execution does. Test both sides of every branch and trace a small example before relying on a larger input.