Control Flow in Python
If
The Python
ifstatement takes a test and a block of statements to carry out if the test is truex = 3 if x > 0 : print('x is positive')
The test can be more complex but must evalute to a Boolean
x = 3 if x > 0 and x < 10: print('x is between 0 and 10')
In fact, for such intervals, you can write it as you might in math
x = 3 if 0 < x < 10: print('x is between 0 and 10')
There can be more than one statement in the block
x = 3 if x > 0 : print('x is positive') print('in other words greater than zero')
As usual in Python, the block is indented more deeply that the
if.An
ifstatement can also have anelsepart:x = -3 if x > 0 : print('x is positive') else: print('x is not positive')
In fact an
ifstatement can have several cases. Each test is evaluated until a true one is found. The corresponding block is then executed.Here is a Python function definition which takes a student's grade in the form of a percentage (a float) and returns a string giving the corresponding AUC letter grade.
def auc_grade(percentage): """Takes a percentage and returns a letter grade following the AUC grading criteria.""" if percentage >= 90 : return 'A+' elif percentage >= 82.5: return 'A' elif percentage >= 77.5: return 'B+' elif percentage >= 72.5: return 'B' elif percentage >= 69: return 'B-' elif percentage >= 66.5: return 'C+' elif percentage >= 63.5: return 'C' elif percentage >= 58.5: return 'C-' elif percentage >= 55: return 'D+' elif percentage >= 53: return 'D' elif percentage >= 51: return 'D-' else: return 'F'
This gives
In [15]: help(auc_grade) Help on function auc_grade in module __main__: auc_grade(percentage) Takes a percentage and returns a letter grade following the AUC grading criteria. In [16]: auc_grade(95) Out[16]: 'A+' In [17]: auc_grade(88) Out[17]: 'A' In [18]: auc_grade(68) Out[18]: 'C+' In [19]: auc_grade(28) Out[19]: 'F'We'll see a more convenient way to to this when we look at Python dictionaries.
Truthiness and Falsiness
Python takes a flexible view of what can appear in the Boolean position of an
if. By default, Python accepts as False the values ‘False’, ‘None’,
numeric zero of all types, and empty strings and empty containers (including
strings, tuples, lists, dictionaries, sets and frozensets). All other values
are interpreted as true.
For
First let's make a list from a string.
day_string = 'monday tuesday wednesday thursday friday saturday sunday' day_list = day_string.split()
This splits
day_stringinto a list of strings, splitting on spaces (whitespace). See the section of strings for details. Now if we ask whatday_listis, we'll see that it is a list of stringsIn [21]: day_list Out[21]: ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
This is more convenient than typing in the list of strings.
We can iterate over a list using a
forstatement. The variable following thefortakes as a value each element of the list in turnIn [25]: for day in day_list: ....: print(day) ....: monday tuesday wednesday thursday friday saturday sunday
We can calculate with the variable just like any other variable:
In [25]: for day in day_list: ....: print('Today it is', day.capitalize()) ....: Today it is Monday Today it is Tuesday Today it is Wednesday Today it is Thursday Today it is Friday Today it is Saturday Today it is Sunday
But lists aren't the only things we can iterate over using a
forloop. We can also iterate over ranges of numbersfor i in range(0, 5): print(i)
The variable
itakes the values from the first (0) up to, but not including, the last (4). (It's worth reading Edsger W. Dijkstra's Why numbering should start at zero)- We can iterate over strings, tuples, sets, dictionaries too.
Some other useful iterations are:
for item in s: for item in sorted(s): for item in set(s): for item in reversed(s): for n, item in enumerate(s): for item in set(s).difference(t):
- In fact we will see shortly that we can make our own kinds of iterables.
Gotchyas
- Modifying a list while iterating over it
If you modify a list while you're interating over it, unpredictable things can happen. This is best avoided.
In [74]: tenlist = list(range(10)) In [75]: tenlist Out[75]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] In [76]: for x in tenlist: ....: print(x, tenlist) ....: tenlist[-x] = 0 ....: 0 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 1 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 2 [0, 1, 2, 3, 4, 5, 6, 7, 8, 0] 3 [0, 1, 2, 3, 4, 5, 6, 7, 0, 0] 4 [0, 1, 2, 3, 4, 5, 6, 0, 0, 0] 5 [0, 1, 2, 3, 4, 5, 0, 0, 0, 0] 0 [0, 1, 2, 3, 4, 0, 0, 0, 0, 0] 0 [0, 1, 2, 3, 4, 0, 0, 0, 0, 0] 0 [0, 1, 2, 3, 4, 0, 0, 0, 0, 0] 0 [0, 1, 2, 3, 4, 0, 0, 0, 0, 0]
While
In Python
whileis used to loop until a (Boolean) condition is met.count = 0 while count < 10: print(count) count = count + 1 print('done')
Of course, we have to be careful that
whiledoesn't loop infinitely unless that's what we want.Here is an example of using a
whileloop for generatively finding a root of the function \(sin(1/x)\) using Newton's method.from math import sin, cos def f(x): return sin(1/x) def df(x): return - cos(1/x) / x**2 def newton(x, epsilon): while abs(f(x)) > epsilon: x = x - f(x) / df(x) return x
Breaking and continuing in loops
Sometimes we want to just break out of a loop and finish executing the entire loop. Sometimes we've had enough of the current value and want to skip to the next value. We can do either of these with
breakandcontinuefor n in range(10): print('found', n, 'once') if n == 8: break if n > 2: continue print('found', n, 'twice') found 0 once found 0 twice found 1 once found 1 twice found 2 once found 2 twice found 3 once found 4 once found 5 once found 6 once found 7 once found 8 once
Iterables, generators & yielding
The Python
yieldoperator is similar toreturn.def multiples(x): yield 2*x
You can
yieldmore than oncedef multiples(x): yield 2*x yield 3*x
A Python function that yields is a generator. It generates each yielded value in turn. We can use it as an iterable
>>> for m in multiples(11): ... print(m) ... 22 33
We can have our generator yield many times.
>>> def multiples(x): ... for m in range(9): ... yield m*x ... >>> for multiple in multiples(11): ... print(multiple) ... 0 11 22 33 44 55 66 77 88 >>>
We can also build a generator object by using a kind of comprehension notation:
for double in (2*x for x in [1,2,3]): print(double)
Or indeed make a generator function using
yielddef doubler(): for x in [1, 2, 3]: yield 2 * x for double in doubler(): print(double)