Introduction to Python

davidbpython.com




In-Class Exercise Solutions, Session 9



PLEASE REFER to pythonreference.com for syntax to follow in coding these Exercises

 

FUNCTIONS: REVIEW

 
Ex. 9.1 Write a function that takes an argument and returns a value.

Function doubleit() takes one argument and returns its argument value doubled.

def doubleit(arg):        # arg: int, 5
    darg = arg * 2        # int, 10
    return darg           # return 10


y = 5                     # int, 5


dy = doubleit(y)          # int, 10
print(dy)                 # 10
 
Ex. 9.2 Write another function that takes an argument and returns a value.

Write a function get_greeting() that takes one string argument (a name) and returns "Hello, " followed by the name and an exclamation point.

def get_greeting(person):          # person: str, 'World' (1st call below)
    s = f'Hello, {person}!'        # str, 'Hello, World!'
    return s                       # return str


x = 'World'                        # str, 'World'
y = 'Guido'                        # str, 'Guido'


w = get_greeting(x)                # str, 'Hello, World!'
print(w)


x = get_greeting(y)                # str, 'Hello, Guido!'
print(x)
 
Ex. 9.3 Write a function that takes two arguments and returns one value.

Define function multiplyem() that takes two numbers, multiplies them together, and returns the product.

def multiplyem(vala, valb):        # vala: int, 5; valb: int, 10
    prod = vala * valb             # int, 50
    return prod                    # return 50


a = 5                              # int, 5
b = 10                             # int, 10

c = multiplyem(a, b)               # int, 50

print(c)
 
Ex. 9.4 Write a function that takes one argument and returns two values.

Function mul_and_div takes an int argument and returns the value doubled and the value halved (/2)

def mul_and_div(value):        # value: int, 5
    dv = value * 2             # int, 10
    hv = value / 2             # float, 2.5
    return dv, hv              # return 10, 2.5


a = 5                          # int, 5

d, h = mul_and_div(a)          # int 10, float 2.5

print(d)                       # 10
print(h)                       # 2.5
 
Ex. 9.5 Write a function that takes one positional (required) argument and one keyword (optional) argument.

Define function mul, which should take a required int argument and an optional int argument. If the optional arg is not passed, it should default to 1 (so that the argument value is multiplied by 1 and thus returned unchanged).

def mul(num, multiplier=1):        # num: int, 5; multiplier: int, 3
    prod = num * multiplier        # prod:  int, 15
    return prod                    # return 15



a = 5

b = mul(5, multiplier=3)     # int, 15

c = mul(5)                   # int, 5
 
Ex. 9.6 Write a function that takes two positional (required) arguments and one keyword (optional) argument.

Define function get_field, which should take a required string argument, a required integer argument and an optional string argument (keyword 'sep', with default ','. The function takes a CSV line and an integer index. It splits the line on the separator and returns the field indicated by the integer -- see examples below. If the optional arg is not passed, it should default to ','.

def get_field(s, idx, sep=','):

    items = s.split(sep)
    return items[idx]


v1 = get_field('hey:you:stop', 0, sep=':')   # 'hey'  (splits on the colon, then returns 1st item)

v2 = get_field('this,that,other', 1)         # 'that' (splits on the default comma, then returns 2nd item)
 
Ex. 9.7 Write a function that returns None (without explicitly returning it).

Write function greet(), which simply prints 'Hello, world!'. Printing x should show None.

def greet():                  #
    print('Hello, world!')
    # returns None by default


x = greet()
print(x)                      # None

The function does not need to do anything more to return None. In fact, when a function does not return anything, it returns None.

 
Ex. 9.8 Demonstration: remove a return statement and note the value.

The below function returns the sum of its arguments. First run the program and note the printed value, then remove the return statement to see the printed value.

def get_sum(val1, val2):        # val1: int, 5; val2: int, 10
    valsum = val1 + val2        # int, 15
    # returns None by default


r = get_sum(5, 10)
print(r)                        # None

This exercise is intended to emphasize that a function without a return statement will always return None. You can know that in most cases if you see None returned from a function, this means it was not intended to return a value and so should be called without an assignment (e.g., without r = above).

 

MULTI-TARGET ASSIGNMENT

 
Ex. 9.9 Explore multi-target assignment errors.

Try removing a variable from either the left or right side of the =. What happens?

a = 5                 # int, 5
b = 10                # int, 10
c = 15                # int, 15

x, y, z = a, b        # ValueError:  not enough values to unpack

x, y = a, b, c        # ValueError:  too many values to unpack
 

FUNCTIONS: VARIABLE SCOPES

 
Ex. 9.10 Explore function scoping.

Call this function, then attempt to print lvar after calling the function. Is lvar available outside the function?

def do(arg):
    lvar = arg * 2
    return lvar


a = do(5)
print(a)

print(lvar)                  # NameError:  name 'lvar' is not defined
 
Ex. 9.11 Explore global variables inside functions.

Replace 2 with gvar inside the function, then call the function. Is gvar available inside the function?

gvar = 2

def do(arg):
    lvar = arg * gvar        # 10 (local arg * global gvar)
    return lvar


a = do(5)
print(a)                     # 10  (yes, globals are available everywhere)
 
Ex. 9.12 Identify local and global variables.

Identify the 3 local variables, 3 global variables and 2 builtin varaibles in the below code:

filename = '../pyku.txt'        # 'filename':  global

                                # 'get_text':  global (function name is a
                                #                      variable as well)
def get_text(fname):            # 'fname':     local
    fh = open(fname)            # 'fh':        local; 'open':  builtin
    text = fh.read()            # 'text':      local
    return text

txt = get_text(filename)        # 'txt':       global
print(txt)                      # 'print':     builtin
 

REVIEW: RAISE STATEMENT

 
Ex. 9.13 Raise an exception. Test to see if the user's input matches one of the values in the valid_choices list (use if uchoice not in valid_choices). If not, raise a ValueError exception with a descriptive error message.
def validate_choice(uchoice):

    valid_choices = ['run', 'stop', 'rewind']

    if uchoice not in valid_choices:
        raise ValueError('must be one of "run", "stop" or "rewind"')


validate_choice('run')           # should have no visible effect - function did not raise

validate_choice('fastforward')   # should raise ValueError with a message
 
Ex. 9.14 Detect object type and raise TypeError. Use the isinstance() function to see if the argument to this function is an integer. If it isn't, raise your own TypeError exception with a descriptive error message.
def doubleit(arg):                                   # arg:  str, '5'
    if not isinstance(arg, int):                     # bool, True
        raise TypeError("arg must be an int")        # exception is raised
    return arg * 2

x = doubleit('5')
 

LAB 1

 
Ex. 9.15 Multi-target assignment.

In one statement, assign the variables a, b and c to x, y and z respectively.

a = 5                    # int, 5
b = 10                   # int, 10
c = 15                   # int 15

x, y, z = a, b, c        # 5, 10, 15


print(x)                 # 5
print(y)                 # 10
print(z)                 # 15
 
Ex. 9.16 Write a function that validates its argument.

Define function make_case(), which takes two arguments: text, a string to be modified, and case a string that must be either 'upper' or 'lower'. If case is not one of these, the function should raise a ValueError exception. Then based on the case argument, return the string uppercased or lowercased.

def make_case(text, case):                    # text: str, 'Hello.', case: str, 'middle' (3rd call below)
    if case != 'upper' and case != 'lower':   # bool, True
        raise ValueError(f'"{case}" is not a valid argument:  must be "upper" or "lower"') # raises

    if case == 'upper':
        return text.upper()
    else:
        return text.lower()


greeting = 'Hello.'                           # str, 'Hello.'

x = make_case(greeting, 'upper')              # str, 'HELLO.'
print(x)

y = make_case(greeting, 'lower')              # str, 'hello.'
print(y)

z = make_case(greeting, 'middle')             # ValueError:  "middle" is not a valid argument:
                                              #              must be "upper" or "lower"
 
Ex. 9.17 Write a function with an optional argument.

Modify the above function so that the 2nd argument is optional, with default 'upper'. Make sure it behaves as shown when called as shown below.

def make_case(text, case='upper'):                 # text: str, 'Hello.'; case: 'upper' (default, 3rd call below)
    if case != 'upper' and case != 'lower':        # bool, False
        raise ValueError(f'"{case}" is not a valid argument:  must be "upper" or "lower"')#

    if case == 'upper':                            # bool, True
        return text.upper()
    else:
        return text.lower()



greeting = 'Hello.'                                # str, 'Hello.'

a = make_case(greeting, case='lower')              # str, 'hello.'
print(a)

b = make_case(greeting, case='upper')              # str, 'HELLO.'

c = make_case(greeting)                            # str, 'HELLO.'
print(c)

d = make_case(greeting, case='title')              # ValueError:  "title" is not a valid argument:
print(d)                                           # must be "upper" or "lower"
 
Ex. 9.18 Write a function with both positional and optional arguments.

Write function temp_convert() that takes one required argument temp, a temperature value, and an optional argument scale=, which must be 'C' or 'F', and a default value of 'C'. If scale is not 'C' or 'F', the function raises a ValueError. Formula for F->C: (x - 32) * 5/9 Formula for C->F: (x * 9/5) + 32 Make sure the function behaves as shown below with the below arguments.

def temp_convert(temp, scale='C'):               # temp: int, 32; scale: str, 'C' (3rd call below)
    if scale not in ['F', 'C']:                  # bool, False
        raise ValueError(f'"{scale}" is not a valid argument:  must be "C" or "F"')  #
    if scale == 'F':                             # bool, False
        return (temp * 9/5) + 32
    else:
        return (temp-32) * 5/9                   # return 0.0

c = temp_convert(212, scale='C')                 # 100
print(c)

f = temp_convert(0, scale='F')                   # 32.0
print(f)

cc = temp_convert(32)                            # 0.0
print(cc)

ff = temp_convert(-1, scale='Fahrenheit')        # ValueError:  "Fahrenheit" is not a
                                            # valid argument:  must be "C" or "F"
print(ff)
 
Ex. 9.19 Write a function that returns multiple values.

Define function name_split(), which takes a single string and attempts to split it on whitespace into 2 or 3 items. If there are more than 3 or fewer than 2 items, it raises a ValueError with a descriptive message. If there are three items, it returns them; if there are two items, it returns the first item, None, and the second item. Make sure the function return values are as shown below.

def name_split(text):                                     # str, 'George Patrick Flanahanahan' (1st call below)
    items = text.split()                                  # list, ['George', 'Patrick', 'Flanahanahan']
    if len(items) != 2 and len(items) != 3:               # bool, False
        raise ValueError('must be 2 or 3 words in name')
    if len(items) == 2:                                   # bool, False
        return items[0], None, items[1]
    else:
        return items                                      # return ['George', 'Patrick', 'Flanahanahan']


first, second, third = name_split('George Patrick Flanahanahan')
print(first, second, third)                                      # 'George', 'Patrick', 'Flanahanahan'

fname, sname, tname = name_split('Aimee Vonda')
print(fname, sname, tname)                                       # 'Aimee', None, 'Vonda'

fn, sn, tn = name_split('Gimpy P. W. Simpson')
print(fn, sn, tn)                                                # ValueError:  must be 2 or 3 words in name
 
Ex. 9.20 Identify global and local variables.

Identify the global and local names in the below code. There are 3 local and 4 global names to be identified.

# local:   c, d, 3
# global:  a, b, x, do (a function is a variable)

a = 5                # a:  global

def do(c, d):        # do:  global; c, d:  local
    e = c * d        # e:     local
    return e

b = 100              # b:  global

x = do(a, b)         # x:  global
print(x)             # 500
 

MODULES

 
Ex. 9.21 Import a module and use its variables. Import module 'mymod' (located in the 'lib' directory) and print one of its variables.
import sys
sys.path.append('../lib')        # temporary - adds mymod.py's directory
                                 #             to the sys.path list (your import path)
                                 #             (should not be used outside of class)

import mymod

print(mymod.PI)                  # 3.14
 
Ex. 9.22 Import a module as a different name and use its variables. Perform the same as above but import the module as 'mm'. Again, print one of the varibles from mymod.py.
import sys
sys.path.append('../lib')        # temporary - adds mymod.py's directory
                                 #             to the sys.path list (your import path)
                                 #             (should not be used outside of class)

import mymod as mm
print(mm.primelist)              # [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 ]
 
Ex. 9.23 Import a variable from a module into the program's namespace.

Perform the same as above but import a variable from 'mymod.py' directly into this program's namespace. You should be able to print this variable without prepending the name with mymod or mm. Again, print one of the varibles.

import sys

sys.path.append('../lib')         # temporary - adds mymod.py's diretory
                                  #             to the sys.path list (your import path)
                                  #             (should not be used outside of class)

from mymod import doubleit

val = doubleit(5)                 # 10
 
[pr]