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
|
|