ICP22 lecture notes

Thursday, September 15

topics for the day:


quick quiz

Consider the following function:

def mystery(a):
    b = 1
    for _ in range(a):
        b = b * a
    return b
  1. What would be the result of evaluating:

    >>> mystery(3)

    answer:


  2. Briefly(!), what does the function compute? For example: “Returns the sum of the first n numbers.”:

    answer: Returns a raised to the a power.


Evaluating loops

Consider this familiar function:

def factorial(n):
    product = 1
    counter = 1
    for _ in range(n):
        product = product * counter
        counter = counter + 1
    return product

How does Pythone evaluate factorial(4)?

times through loop   n   product   counter
------------------   -   ------    ------- 
     0               4      1         1
     1               4      1         2
     2               4      2         3
     3               4      6         4
     4               4     24         5
------
return 24

(try this example using pythontutor)


In for _ in range(...) the underscore (_) is actually a variable, but it means we will ignore its value.

In contrast, when iterating over a string using for ... in <some string> as in:

for c in s:

the definite loop repeates a number of times equal to the length of the string (in this case the value of the variable s); each time through the loop the loop variable (in this case called c, but it can be named just as we name any other variable) takes on the next character in s. Consider:

def reverse(s):
    """Returns new string which is reverse of s.

    >>> reverse('TAB')
        'BAT'
    """
    t = ''
    for c in s:
        t = c + t
    return t

and then evaluating reverse('TAB'):

s         t        c
--------------------
'TAB'     ''       not yet defined
--- entering the loop ---
'TAB'     ''       'T'
'TAB'     'T'      'A'
'TAB'     'AT'     'B'
---- done with the loop ---
'TAB'     'BAT'    no longer needed

(try a similar example using pythontutor


strings are sequences of characters

we have already mentioned that strings are sequences of characters and by characters we mean, in general, text symbols that loosely correspond to keyboard symbols; in Python characters are (circularly!) strings of length 1; but in many other PLs (and in general), characters are thought as distinct (and simpler things). The key concept is that characters are standardized: for decades, computer scientists across the globe have agreed that each character that can be displayed (or that has a standard meaning like \n for advancing the display to a new line) correspond to a positive whole number. First there was the ASCII code; now there is Unicode which is a superset of ASCII. (In this course we will mostly rely on ASCII). The code tells us that that a string such as

`CAB`

corresponds to a sequence of numbers, in this case:

67   65   66

simple takeaways about ASCII:

in Python we can find the ASCII code of a character using the built-in ord function:

>>> ord('A')
    65

we can use that in a loop like:

>>> for ch in 'Help me!':
        print(ord(ch))
    72
    101
    108
    112
    32
    109
    101
    33

there is also the inverse functon, chr, which takes a positive whole numbers and returns the correspond ASCII (or Unicode) symbol as a one-character string:

>>> chr(66)
    'B'

we can use ord and chr togehter in a function like:

def shift1(word):
    """Return new string that is each character of s shifted one place.

    >>> shift1('HAL')
        'IBM'
    """
    shifted_word = ''
    for symbol in word:
        original_code = ord(symbol)
        new_code = original_code + 1
        new_symbol = chr(new_code)
        shifted_word = shifted_word + new_symbol
    return shifted_word

Looking ahead, we can see what happens when we do this:

def weird(s):
    t = ''
    for ch in s:
        t = t + (chr(ord(ch) + 32))
    return t

and then:

>>> weird('WHATEVER')
    'whatever'
>>> weird('HELP ME!')
    'help@meA'