Week 6

Scope, While Loops, and String Operations

Author:Christopher Haynes
Email:chaynes@indiana.edu
Affiliation:Indiana University
Course:BL CSCI A201
Date:2008-02-21
Copyright © 2008, Christopher Haynes—all rights reserved.

Scope demo

>>> def fun(param):
        local_var = 3
        print local_var, param, global_var
>>> global_var = 4
>>> fun(2)
3 2 4
>>> def fun2():
        print local_var
>>> fun2()
Traceback (most recent call last):
  File "", line 1, in ?
  File "", line 2, in fun2
NameError: global name 'local_var' is not defined
>>> def fun3():
        global_var = 5 # this actually creates a local variable
        print global_var
>>> fun3()
5
>>> global_var
4

Local vs. global variables

Scope of variables

While loop statement

While loop control flow diagram

while.png

Direct exits from a loop body

Example: powers

def powers(n):
    """
    Prints a table of the first n integers and the corresponding
    power of two.
    >>> powers(10)
    1 2
    2 4
    3 8
    4 16
    5 32
    6 64
    7 128
    8 256
    9 512
    10 1024
    >>>
    """
    i = 1
    while i <= n:
        print i, 2**i
        i = i + 1

Counted loops

Avoiding infinite loops

Most loops exit when the value of a variable referenced in the loop's test expression changes in a way that makes the expression false

Accumulator loops

Exercise: powers_acc

def powers_acc(n):
    """
    Same as powers(n), but use an accumulator and not the
    exponentiation operator.
    Hint: initialize the accumulator to 2 and multiply it by
    two with each iteration.
    >>> powers_acc(3)
    1 2
    2 4
    3 8
    >>>
    """
    #.
    #.
    #.
    #.
    #.
    #.

Solution: powers_acc

def powers_acc(n):
    """
    Same as powers(n), but use an accumulator and not the
    exponentiation operator.
    Hint: initialize the accumulator to 2 and multiply it by
    two with each iteration.
    >>> powers_acc(3)
    1 2
    2 4
    3 8
    >>>
    """
    i = 1
    accumulator = 2
    while i <= n:
        print i, accumulator
        accumulator = accumulator * 2
        i = i + 1

Review: printing vs. returning

clicker If a function f is supposed to return a value (other than None), must f contain a return statement in its body?

  1. Yes
  2. No, the return statement might be in the body of a function that is called from the body of f
  3. No, values can be returned in other ways

Answer: A

clicker If a function f is supposed to print a value, must f contain a print statement in its body?

  1. Yes
  2. No, the print statement might be in a function that is called from the body of f

Answer: B

clicker Which of the following defines a global variable named x containing 3?

  1. def x(): 3
  2. x == 3
  3. x = 3
  4. x <= 3

Answer: C

clicker Which of the following is not a Python comparison operator?

  1. !=
  2. =<
  3. ~=
  4. all of the above
  5. B and C

Answer: E

clicker The value of 2<1 or not 2<3 and 3<4 is

  1. True
  2. False
  3. there is an error

Answer: B

Review exercise: ordinal_form function

Solutions: ordinal_form function

def ordinal_form(n):
    # assume n is an integer in the range from 1 through 20
    if n == 1:
        return '1st'
    elif n == 2:
        return '2nd'
    elif n == 3:
        return '3rd'
    else:
        return str(n) + 'th'

clicker Which of the following is true just when x is in the range from 0 to 10, inclusive of both endpoints?

  1. 0 <= x and x <= 10
  2. (x >= 0) and (x <= 10)
  3. A and B
  4. none of the above

Answer: C

clicker How would you rate the first assignment?

  1. rather easy
  2. about right in difficulty
  3. too hard

clicker How are you doing in the current assignment?

  1. We're making some progress
  2. We're really stuck
  3. We haven't really worked on it yet

clicker How would you rate the last lab?

  1. rather easy
  2. about right in difficulty
  3. too hard

Demo: String escape characters

>>> print 'line 1\nline 2'
line 1
line 2
>>> print 'a\ttab'
a   tab
>>> print 'He said "What?"'
He said "What?"
>>> print "That's ok"
That's ok
>>> print 'He said "That\'s ok"'
He said "That's ok"
>>> print "He said \"That's ok\""
He said "That's ok"
>>> print "dir\\subdir"
dir\subdir
>>> 'dir\\subdir'
'dir\\subdir'
>>> 'a\xy'
ValueError: invalid \x escape

String escape characters

Demo: String operators and len function

::
>>> 'one string' + 'and another'
'one stringand another'
>>> print 'Answer: ' + 3.14 * 5
Traceback (most recent call last):
  File "", line 1, in ?
TypeError: cannot concatenate 'str' and 'float' objects
>>> print 'Answer: ' + str(3.14 * 5)
Answer: 15.7
>>> 'Answer: ' + 42
TypeError: cannot concatenate 'str' and 'int' objects
>>> 'Answer: ' + str(42)
'Answer: 42'
>>> int(' 3\n')
3
>>> int('1 + 2')
ValueError: invalid literal for int(): 1 + 2
>>> len('py')
2
>>> len('')
0
>>> 'NI' * 3
'NININI'
>>> ' ' * 5
'     '
>>>

String operators and len function

Overloaded operators

Right and left justification

Defining a right-justification function

def right_justify(n, string):
    """
    Returns the string with enough blanks added at the beginning
    to make it n characters long.
    >>> right_justify(5, 'foo')
    '  foo'
    >>>
    """
    return ' ' * (n - len(string)) + string

FYI Python, like most languages, has a somewhat complicated formatting mechanism that allows justification and some other formatting possibilities to be expressed in a very compact way. But that's beyond this course, and sometimes you still have to know how to do it yourself anyway.

Example: mult_table

def mult_table(n):
    """
    Print an n by n multiplication table.
    >>> mult_table(9)
    1 2 3 4 5 6 7 8 9
    2 4 6 8 10 12 14 16 18
    3 6 9 12 15 18 21 24 27
    4 8 12 16 20 24 28 32 36
    5 10 15 20 25 30 35 40 45
    6 12 18 24 30 36 42 48 54
    7 14 21 28 35 42 49 56 63
    8 16 24 32 40 48 56 64 72
    9 18 27 36 45 54 63 72 81
    >>>
    """
    i = 1
    while i <= n:
        j = 1
        line = ''
        while j <= n:
            line = line + str(i * j) + ' '
            j = j + 1
        print line
        i = i + 1

Nested loops

Exercise: justified_mult_table

def justified_mult_table(n, width):
    """
    Print an n by n multiplication table in which each column has
    the indicated width.
    >>> justified_mult_table(9, 4)
       1   2   3   4   5   6   7   8   9
       2   4   6   8  10  12  14  16  18
       3   6   9  12  15  18  21  24  27
       4   8  12  16  20  24  28  32  36
       5  10  15  20  25  30  35  40  45
       6  12  18  24  30  36  42  48  54
       7  14  21  28  35  42  49  56  63
       8  16  24  32  40  48  56  64  72
       9  18  27  36  45  54  63  72  81
    >>>
    """
    i = 1
    while i <= n:
        j = 1
        line = ''
        while j <= n:
            #...
            j = j + 1
        print line
        i = i + 1

Solution: justified_mult_table

def justified_mult_table(n, width):
    """
    Print an n by n multiplication table in which each column has
    the indicated width.
    >>> justified_mult_table(9, 4)
       1   2   3   4   5   6   7   8   9
       2   4   6   8  10  12  14  16  18
       3   6   9  12  15  18  21  24  27
       4   8  12  16  20  24  28  32  36
       5  10  15  20  25  30  35  40  45
       6  12  18  24  30  36  42  48  54
       7  14  21  28  35  42  49  56  63
       8  16  24  32  40  48  56  64  72
       9  18  27  36  45  54  63  72  81
    >>>
    """
    i = 1
    while i <= n:
        j = 1
        line = ''
        while j <= n:
            line = line + right_justify(width, str(i * j))
            j = j + 1
        print line
        i = i + 1

Exercise: powers_formatted

def powers_formatted(n):
    """
    Prints a table of the first n integers and the corresponding
    power of two.
    Right justify the integers in two columns and the power in 6,
    with a space between the columns.
    >>> powers_formatted(10)
     1      2
     2      4
     3      8
     4     16
     5     32
     6     64
     7    128
     8    256
     9    512
    10   1024
    >>>
    """
    i = 1
    while i <= n:
        #...
        #...
        print formatted_i, formatted_power
        i = i + 1

Solution: powers_formatted

def powers_formatted(n):
    """
    Prints a table of the first n integers and the corresponding
    power of two.
    Right justify the integers in two columns and the power in 6,
    with a space between the columns.
    >>> powers_formatted(10)
     1      2
     2      4
     3      8
     4     16
     5     32
     6     64
     7    128
     8    256
     9    512
    10   1024
    >>>
    """
    i = 1
    while i <= n:
        formatted_i = right_justify(2, str(i))
        formatted_power = right_justify(6, str(2**i))
        print formatted_i, formatted_power
        i = i + 1

Formatting floating point numbers