More Control Flow Tools¶
Besides the while statement just introduced, Python knows the usual
control flow statements known from other languages, with some twists.
if Statements¶
Perhaps the most well-known statement type is the if statement. For
example:
from microbit import *
x = 42
if x < 0:
x = 0
display.scroll('Negative, change to zero')
elif x == 0:
display.scroll('Zero')
elif x == 1:
display.scroll('Single')
else:
display.scroll('More')
# it will display More on the LED screen
Alternatively, you can use the REPL function for this example:
# use the REPL function for this
>>> x = 42
>>> if x < 0:
... x = 0
... print('Negative changed to zero')
... elif x == 0:
... print('Zero')
... elif x == 1:
... print('Single')
... else:
... print('More')
...
More
There can be zero or more elif parts, and the else part is
optional. The keyword ‘elif’ is short for ‘else if’, and is useful
to avoid excessive indentation. An if … elif …
elif … sequence is a substitute for the switch or
case statements found in other languages.
for Statements¶
The for statement in Python differs a bit from what you may be used
to in C or Pascal. Rather than always iterating over an arithmetic progression
of numbers (like in Pascal), or giving the user the ability to define both the
iteration step and halting condition (as C), Python’s for statement
iterates over the items of any sequence (a list or a string), in the order that
they appear in the sequence. For example (no pun intended):
from microbit import *
words = ['cat', 'window', 'dog']
for w in words:
display.scroll(w)
sleep(500)
# it will display cat, window and dog consecutively
The range() Function¶
If you do need to iterate over a sequence of numbers, the built-in function
range() comes in handy. It generates arithmetic progressions:
from microbit import *
for i in range(5):
display.show(i)
sleep(500)
# it will display 0 to 4 one after the other
Alternately, you can use the REPL to run the same example:
>>> for i in range(5):
... print(i)
...
0
1
2
3
4
The given end point is never part of the generated sequence; range(10) generates
10 values, the legal indices for items of a sequence of length 10. It
is possible to let the range start at another number, or to specify a different
increment (even negative; sometimes this is called the ‘step’):
range(5, 10)
5, 6, 7, 8, 9
range(0, 10, 3)
0, 3, 6, 9
range(-10, -100, -30)
-10, -40, -70
In many ways the object returned by range() behaves as if it is a list,
but in fact it isn’t. It is an object which returns the successive items of
the desired sequence when you iterate over it, but it doesn’t really make
the list, thus saving space.
We say such an object is iterable, that is, suitable as a target for
functions and constructs that expect something from which they can
obtain successive items until the supply is exhausted. We have seen that
the for statement is such an iterator. The function list()
is another; it creates lists from iterables:
# Use the REPL function for this task
>>> list(range(5))
[0, 1, 2, 3, 4]
Later we will see more functions that return iterables and take iterables as argument.
break and continue Statements, and else Clauses on Loops¶
The break statement, like in C, breaks out of the innermost enclosing
for or while loop.
Loop statements may have an else clause; it is executed when the loop
terminates through exhaustion of the list (with for) or when the
condition becomes false (with while), but not when the loop is
terminated by a break statement. This is exemplified by the
following loop, which searches for prime numbers:
# Use the REPL function of the mu editor for this
>>> for n in range(2, 10):
... for x in range(2, n):
... if n % x == 0:
... print(n, 'equals', x, '*', n//x)
... break
... else:
... # loop fell through without finding a factor
... print(n, 'is a prime number')
...
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3
(Yes, this is the correct code. Look closely: the else clause belongs to
the for loop, not the if statement.)
When used with a loop, the else clause has more in common with the
else clause of a try statement than it does that of
if statements: a try statement’s else clause runs
when no exception occurs, and a loop’s else clause runs when no break
occurs. For more on the try statement and exceptions, see
tut-handling.
The continue statement, also borrowed from C, continues with the next
iteration of the loop:
# use the REPL function for this task
>>> for num in range(2, 10):
... if num % 2 == 0:
... print("Found an even number", num)
... continue
... print("Found a number", num)
Found an even number 2
Found a number 3
Found an even number 4
Found a number 5
Found an even number 6
Found a number 7
Found an even number 8
Found a number 9
Defining Functions¶
We can create a function that writes the Fibonacci series to an arbitrary boundary:
from microbit import *
def fib(n): # write Fibonacci series up to n
a,b = 0,1
while a < n:
a,b = b,a+b
display.scroll(a)
fib(2000) # will display 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
- Alternately, you can accomplish this task using the REPL function on your mu edior::
>>> def fib(n): # write Fibonacci series up to n ... """Print a Fibonacci series up to n.""" ... a, b = 0, 1 ... while a < n: ... print(a, end=' ') ... a, b = b, a+b ... print() ... >>> # Now call the function we just defined: ... fib(2000) 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
The keyword def introduces a function definition. It must be
followed by the function name and the parenthesized list of formal parameters.
The statements that form the body of the function start at the next line, and
must be indented.
It is simple to write a function that returns a list of the numbers of the Fibonacci series, instead of printing it:
>>> def fib2(n): # return Fibonacci series up to n
... """Return a list containing the Fibonacci series up to n."""
... result = []
... a, b = 0, 1
... while a < n:
... result.append(a) # see below
... a, b = b, a+b
... return result
...
>>> f100 = fib2(100) # call it
>>> f100 # write the result
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
This example, as usual, demonstrates some new Python features:
- The
returnstatement returns with a value from a function.returnwithout an expression argument returnsNone. Falling off the end of a function also returnsNone. - The method
append()shown in the example is defined for list objects; it adds a new element at the end of the list. In this example it is equivalent toresult = result + [a], but more efficient.
More on Defining Functions¶
It is also possible to define functions with a variable number of arguments. There are three forms, which can be combined.
Default Argument Values¶
The most useful form is to specify a default value for one or more arguments. This creates a function that can be called with fewer arguments than it is defined to allow. For example:
def ask_ok(prompt, retries=4, reminder='Please try again!'):
while True:
ok = input(prompt)
if ok in ('y', 'ye', 'yes'):
return True
if ok in ('n', 'no', 'nop', 'nope'):
return False
retries = retries - 1
if retries < 0:
raise ValueError('invalid user response')
print(reminder)
This function can be called in several ways:
- giving only the mandatory argument:
ask_ok('Do you really want to quit?') - giving one of the optional arguments:
ask_ok('OK to overwrite the file?', 2) - or even giving all arguments:
ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')
This example also introduces the in keyword. This tests whether or
not a sequence contains a certain value.
The default values are evaluated at the point of function definition in the defining scope, so that
i = 5
def f(arg=i):
print(arg)
i = 6
f()
will print 5.
Important warning: The default value is evaluated only once. This makes a difference when the default is a mutable object such as a list, dictionary, or instances of most classes. For example, the following function accumulates the arguments passed to it on subsequent calls:
def f(a, L=[]):
L.append(a)
return L
print(f(1))
print(f(2))
print(f(3))
This will print
[1]
[1, 2]
[1, 2, 3]
If you don’t want the default to be shared between subsequent calls, you can write the function like this instead:
def f(a, L=None):
if L is None:
L = []
L.append(a)
return L
Intermezzo: Coding Style¶
Now that you are about to write longer, more complex pieces of Python, it is a good time to talk about coding style. Most languages can be written (or more concise, formatted) in different styles; some are more readable than others. Making it easy for others to read your code is always a good idea, and adopting a nice coding style helps tremendously for that.
For Python, PEP 8 has emerged as the style guide that most projects adhere to; it promotes a very readable and eye-pleasing coding style. Every Python developer should read it at some point; here are the most important points extracted for you:
Use 4-space indentation, and no tabs.
4 spaces are a good compromise between small indentation (allows greater nesting depth) and large indentation (easier to read). Tabs introduce confusion, and are best left out.
Wrap lines so that they don’t exceed 79 characters.
This helps users with small displays and makes it possible to have several code files side-by-side on larger displays.
Use blank lines to separate functions and classes, and larger blocks of code inside functions.
When possible, put comments on a line of their own.
Use spaces around operators and after commas, but not directly inside bracketing constructs:
a = f(1, 2) + g(3, 4).Name your functions consistently; the convention is to use
lower_case_with_underscoresfor functions and methods.Don’t use fancy encodings if your code is meant to be used in international environments. Python’s default, UTF-8, or even plain ASCII work best in any case.
Likewise, don’t use non-ASCII characters in identifiers if there is only the slightest chance people speaking a different language will read or maintain the code.
Footnotes
| [1] | Actually, call by object reference would be a better description, since if a mutable object is passed, the caller will see any changes the callee makes to it (items inserted into a list). |