Python Basics – Control Flow
Jan 11, 2019 • 12 Minute Read
Introduction
Programs that only assign variables and print out strings are, well, boring! Things get more interesting when you have to make choices, performing a certain action based on some condition, another action based on another. This guide will show you how to make branching decisions, how to conditionally execute code, as well as how to use common looping constructs.
Simple Condition
The simplest branching decision is comparing one thing to another. In Python, the if statement evaluates a condition and executes the block which follows it only when the condition is met.
>>> if 1 == 1:
... print('1 is 1')
...
1 is 1
>>>
In the example above, we are asking that Python should print '1 is 1' if the condition 1 == 1 is true. When you run the statements above, the condition is in fact met, and the print statement would execute.
The if statement is of the general form:
if [CONDITION]:
BLOCK
Where the if keyword is followed by a condition, the condition is followed by a colon (:) and a newline, then an indented block of statements to be executed when the condition is met. The condition can be any logical condition, as long as it can be evaluated for truthfulness - more on that in a bit.
You may have noticed that the condition is "bare", not surrounded by parenthesis. Python was designed to be terse and clutter-free - eschewing braces, parenthesis and other enclosing symbols for expressions unless absolutely necessary. The if condition must be terminated with a colon, which is the clue for the Python parser to know that the condition portion is ended.
What follows the colon is a line-break and an indented block. Python uses white-space to distinguish code blocks. You can use spaces or tabs to create a block. When several statements use the same indentation, they are considered a block. Python in fact insists that separate statements use the same indentation in a block. It would complain if you forget to indent when a block is expected, as well as if you use varying indentations. This example fails to indent after the if statement:
>>> if 1 == 1:
... print('not indented')
File "<stdin>", line 2
print('not indented')
^
IndentationError: expected an indented block
This example over-indents the second print statement:
>>> if 1 == 1:
... print('I am indented')
... print('I am too indented')
File "<stdin>", line 3
print('I am too indented')
^
IndentationError: unexpected indent
While this example under-indents the second print statement:
>>> if 1 == 1:
... print('3 spaces indent')
... print('2 spaces indent')
File "<stdin>", line 3
print('2 spaces indent')
^
IndentationError: unindent does not match any outer indentation level
>>>
Most modern IDEs (Integrated Development Environment) help you keep indentation using tabs or spaces, but since whitespace characters are not visible in some editors, you should take care to properly indent blocks - the source of oh-too-many programming errors.
For short statements, you can also write a single line condition:
>>> if True: print('yes')
...
yes
Truthfulness
A condition is considered true when the interpreter evaluates it and finds it to either be True or have a non-None (null in other languages) value. The following conditions are all true, and will produce a printed response:
>>> if 42: print('yes - number')
...
yes - number
>>> if 'Marklar': print('yes - string')
...
yes - string
>>> if 'fun' in 'function' : print('yes - logical test')
...
yes - logical test
>>>
Python conditions are not met when the expression evaluates to False or is None. The following conditions will not be met, and result in nothing being printed:
>>> if False: print('no')
...
>>> x = None
>>> if x: print('no')
...
>>> if 1 == 2: print('no')
...
>>> if 'i' in 'team': print('no')
...
>>>
In some languages such as JavaScript you may test a "variable" for existence. Python does not have such a built in notion. The following if statement will produce an error unless the variable thing was previously created:
>>> if thing:
... print('Variable "thing" exists!')
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'thing' is not defined
>>>
The error produced here is not particular to the if statement, but it does illustrate what happens when the condition produces an error rather than a true or false value.
If and Else
More complex branching can be produced by using the else clause in conjunction with if:
>>> if 1 < 1:
... print('1 is less than 1')
... else:
... print('1 is NOT less than 1')
...
1 is NOT less than 1
>>>
The branching decision above executes the second block, printing out '1 is NOT less than 1' because the if condition is not met. Note that the else keyword is indented same as the if keyword, and followed by a semicolon. Using else complements if in executing the respective code block when the if condition is not met.
To check another condition in case the first one was not met, use the elif keyword instead of else, followed by its own condition:
>>> if 1 < 1:
... print('1 is less than 1')
... elif 1 <= 1:
... print('1 is less than or equal to 1')
...
1 is less than or equal to 1
>>>
Above, we see that the second condition 1 <= 1 is met. elif is only evaluated if no preceding condition is met. The following will print "true", not "true too" because the first condition is met, so the elif condition is skipped and not evaluated:
>>> if 1 == 1:
... print('1 is 1')
... elif 1 <= 1:
... print('true too')
...
1 is 1
>>>
A final else: at the end of a chain of if and elif would catch any remaining condition not met by any preceding evaluation:
>>> if 1 < 1:
... print('1 is less than 1')
... elif 1 > 1:
... print('1 is greater 1')
... else:
... print('1 is 1')
...
1 is 1
>>>
Repeating with While
Sometime we want to execute code repeatedly until a condition is met, or while some condition remains true.
>>> while True:
... x = input()
... if x == 'q': break
...
b
b
q
>>>
The input() function prompts the user to enter some text. The code above waits for the user to type in q+[ENTER] in the terminal. Any other character typed will cause it to repeatedly wait for input again. The while condition is always True here, so it seems this would go on forever. But if the user enters q, the if condition would be met and the break would execute, exiting the while loop. The break statement causes the current loop to exit the block immediately and halt the loop.
As before, the while construct expects a colon : after the condition. As long as the condition is met, the block following the condition would execute. It would continue executing until either the condition evaluates to a none-true value (False or None), or until a break statement is encountered in the block.
Looping
It is very common to need to loop a certain number of times, and know which round you are executing. Let's count to three, for example:
>>> x = 1
>>> while x < 4:
... print('X is ', x)
... x = x + 1
...
X is 1
X is 2
X is 3
>>>
The code assigns the variable x 1 to start with, and with each iteration of the while loop, x is incremented by 1. When the condition x < 4 is no longer true - when x is 4 - the loop exits.
For such tasks where a variable holds a value and is then incremented each iteration, there's a cleaner syntax: the for loop. The Python for loop is most commonly used to assign a variable a sequence of values until the sequence is exhausted. Here is counting again - this time with a for loop:
>>> for x in range(1,4):
... print('X is ', x)
...
X is 1
X is 2
X is 3
>>>
This time, we don't need to explicitly bump up x each iteration - the for loop does that for us. The range() function produces a sequence of numbers from 1 to 3. The full signature of the range function is range(_start_,_stop_,_step_). In our case above, the loop exits when x becomes 4. The stop argument to range() is exclusive: it would not be assigned and the block would not execute once the range reached that value.
Using the step argument lets you bump the value by a value other than one. Here is how we can print some even numbers by starting at zero and incrementing by two:
>>> for n in range(0,6,2):
... print('Even ', n)
...
Even 0
Even 2
Even 4
>>>
You can count backwards, setting the step to a negative number:
>>> for n in range(3,0,-1):
... print(n)
...
3
2
1
There is also a shorthand if you want a numeric sequence from zero to some value, using the simplified signature range(_stop_)
>>> for n in range(3):
... print(n)
...
0
1
2
>>>
This simplified range always starts at zero, and terminates with the number below the given stop value. Our example was range(3) so the last number printed in the loop is 2.
The for loop syntax uses the in keyword after the variable name. This should clue us to the fact that the range is some kind of sequence - not necessarily a numeric one! For example, a string is a sequence of characters. We can loop over those characters like so:
>>> for thing in 'Hi':
... print(thing)
...
H
i
>>>
As you can see, each letter from the string 'Hi' is assigned to the variable thing in each iteration of the loop and given to the print() statement in the block.
String is just one of the sequence types you can provide the for loop. Other types include sets, lists, tuples, and range as we saw.
Here's a way to loop over a list of strings:
>>> stooges = ['larry','moe','curly']
>>> for stooge in stooges:
... print(stooge)
...
larry
moe
curly
>>>
The variable stooges is assigned a list of strings. The for loop iterates over the list, assigning the variable stooge one name at the time from the stooges list (in order) and passes it along to the inner block which prints it out.
Break and Continue
As with the while loop, you may stop iterating through a sequence using the break statement:
>>> for d in ['close','far','too far']:
... print(d)
... if d == 'far':
... break
...
close
far
>>>
The loop above broke out of the block when the if condition found that the current value is 'far', so the loop stopped processing before the last item in the sequence got to 'too far'.
Sometimes, it is useful to "skip" a value in a sequence. The keyword continue lets you do just that. Using continue in a block skips execution of any remaining statements in the block, but lets the loop continue with the next value in the sequence.
>>> for fruit in ['orange','bad apple','banana']:
... if 'bad' in fruit:
... continue
... print(fruit)
...
orange
banana
>>>
The loop above continued iterating through all three values in the list of fruits. When the value 'bad apple' was assigned to the fruit variable, the condition 'bad' in fruit was met, so the rest of the block was skipped for that iteration only - the print statement did not execute that time. So the result is that all values except 'bad apple' where printed.
Summary
Branching and looping are core programming tasks that most of us will need to perform on a regular basis. This guide explained how to execute code conditionally using the if statement. You also learned to use the while and for looping constructs in order to repeat execution of a code block, and how to stop such loop execution midway. Using the techniques and concepts from this guide will set you on your way for more advanced and complex programming in Python.