Control Flow in Python

If

  1. The Python if statement takes a test and a block of statements to carry out if the test is true

    x = 3
    if x > 0 :
      print('x is positive')
    
  2. 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')
    
  3. 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')
    
  4. 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.

  5. An if statement can also have an else part:

    x = -3
    if x > 0 :
      print('x is positive')
    else:
      print('x is not positive')
    
  6. In fact an if statement 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

  1. 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_string into a list of strings, splitting on spaces (whitespace). See the section of strings for details. Now if we ask what day_list is, we'll see that it is a list of strings

    In [21]: day_list
    Out[21]: ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
    

    This is more convenient than typing in the list of strings.

  2. We can iterate over a list using a for statement. The variable following the for takes as a value each element of the list in turn

    In [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
    
  3. But lists aren't the only things we can iterate over using a for loop. We can also iterate over ranges of numbers

    for i in range(0, 5):
      print(i)
    

    The variable i takes 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)

  4. We can iterate over strings, tuples, sets, dictionaries too.
  5. 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):
    
  6. 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

  1. In Python while is 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 while doesn't loop infinitely unless that's what we want.

  2. Here is an example of using a while loop 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

  1. 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 break and continue

    for 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

  1. The Python yield operator is similar to return.

    def multiples(x):
      yield 2*x
    
  2. You can yield more than once

    def multiples(x):
      yield 2*x
      yield 3*x
    
  3. 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
    
  4. 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
    >>>
    
  5. 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)
    
  6. Or indeed make a generator function using yield

    def doubler():
        for x in [1, 2, 3]:
            yield 2 * x
    
    
    for double in doubler():
        print(double)
    

Author: Breanndán Ó Nualláin <o@uva.nl>

Date: 2025-03-06 Thu 11:40