This worksheet focuses on exceptions, the os module, and the function- and assignment-related concepts from Lecture 20 (multiple return values, tuples, tuple assignment, variadic functions, iterable unpacking).
Following the new policy, Problem 1 is different in that:
The main course materials to refer to for this worksheet are:
(Lecture videos are not linked on worksheets, but are also useful to review while working on worksheets. Video links can be found in the course course Blackboard site.)
If you want to pass multiple items to a function, there are essentially two ways to do it:
f( [1,2,3] )
)f(1, 2, 3)
)Imagine we want to make a function numberedprint
that prints a numbered list of items. For example, if the items are a
, b
, and c
it might print:
#1: a
#2: b
#3: c
Suppose we want to make this function flexible so that it accepts the items in either of the two ways described above (boxed or not). In other words, you should be able to call it as
numberedprint("a","b","c")
OR
numberedprint( ["a","b","c"] )
and have it produce the same output.
More precisely, the function should do the following:
Hint: Check what kind of exception is raised when you iterate over a non-iterable, like for x in 7:
def numberedprint(*args):
"""
Print a numbered list of items, accepting the items as
separate arguments or as items in a single iterable.
"""
if len(args)==0:
# Nothing to do
return
# Next we'll create an iterable L that contains all the items
if len(args) > 1:
# multiple arguments = each arg is an item
# Just use args itself as the iterable
L = args
else:
onlyarg = args[0]
L = []
try:
for a in onlyarg:
L.append(a)
except TypeError:
# Oops, the only argument is not actually iterable
# Interpret it as the only item instead
L.append(onlyarg)
# Display the results
for i,a in enumerate(L):
print("#{}: {}".format(i+1,a))
Checking the solution on the test cases from the worksheet:
numberedprint("a","b","c") # 3 arguments, so each is an item
numberedprint(True,False) # 2 arguments, so each is an item
numberedprint( ["a","b","c"] ) # one argument, seen as iterable of items
numberedprint(7) # one argument, but it isn't iterable, so it's considered an item
numberedprint() # no arguments = no output
numberedprint("kangaroo") # string is iterable, so this is viewed as an iterable of items (characters)
numberedprint("kangaroo","koala") # 2 arguments, so each is an item
Finally, after you have the function working: How can you call it so that it produces this output?
#1: kangaroo
We pass a list that has the string "kangaroo"
as its only element.
numberedprint( ["kangaroo"] )
Suppose you are taking a class called NDT 371 that gives a homework assignment each week, each of which asks you to write a Python script. For some reason, the problems are always numbered 8 and 9.
Being an enterprising student who is familiar with Python's os
module, you decide to make a quick Python script that will generate template Python files for each problem on each homework. That way, when the homework is assigned, you just open the two files and get started.
Create that script. Specifically, it should do the following:
ndt371
in the current directory.For each homework number N (between 1 and 15) and each problem number P (between 8 and 9), see if a file called hwkNprobP.py
exists in the subdirectory ndt371
. Here, the N and P should be replaced with the actual numbers, so the filenames will be like hwk7prob8.py
and so on.
If no file with that name exists, create one (opening it for writing) and write the following text before closing it.
"""DOCSTRING GOES HERE"""
# NDT371 Fall 2023
# Firstname Lastname
But if a file with that name already exists, the script should leave it alone and print a warning to the terminal, like
Not creating ndt371/hwk3prob8.py: A file with that name already exists
Notice that this function will behave differently the first time it is run (when it will make all the templates). If you immediately run it again, it should simply warn you that all the templates exist, and not do anything to the files.
To fully test the program, you should run it several times, including under these conditions:
ndt371
subdirectory exists, and confirm it makes one with all the template Python filesndt371
but leave the directory itself, and confirm it still creates the filesBe careful opening files for writing. This problem specifies behavior where you check to make sure a file does not exist before you open it for writing, to avoid data loss. This problem was purposely formulated to use filenames that probably won't be the same as programs you make for this class, just in case you make a mistake and write a program that clears some files contents.
"""
Create templates for a semester of homework
"""
# MCS 260 Fall 2021 Worksheet 8 Problem 2
import os
hwkdir = "ndt371"
template = """\"\"\"DOCSTRING GOES HERE\"\"\"
# NDT371 Fall 2023
# Emily Dumas
"""
if os.path.exists(hwkdir):
if not os.path.isdir(hwkdir):
print("{} exists but is not a directory. Exiting.".format(hwkdir))
exit()
else:
os.mkdir(hwkdir)
for N in range(1,16):
for P in range(8,10):
fn = os.path.join(hwkdir,"hwk{}prob{}.py".format(N,P))
if os.path.exists(fn):
print("Not creating {}: A file with that name already exists".format(fn))
else:
fobj = open(fn,"w",encoding="UTF-8")
fobj.write(template)
fobj.close()
Write a script that takes 3 command line arguments, a start value s
(a float), a ratio r
(a float), and a number of terms N
(a nonnegative integer). It should then print the first N
terms of a geometric sequence where the first term is s
and the ratio of successive terms is r
, e.g.
python geomprog.py 2 3 5
2.0
6.0
18.0
54.0
162.0
In this example, the sequence starts at 2, has a ratio of 3, and 5 terms are shown.
However---and this is the key goal of this problem---you should make this program robust against invalid input of all kinds. For example, it should handle all of the following conditions by printing a useful message and exiting normally:
float()
int()
s=1
, r=123456789
, N=50
, and notice that the program halts with an error)Ideally, the result should be a Python script that, regardless of the command line arguments it receives, never exits with an uncaught exception.
"""
Print terms in finite geometric progression
"""
# MCS 260 Fall 2021 Worksheet 8 Problem 3
import sys
def usage():
"""
print a usage message and exit
"""
print("Usage: {} start ratio num_terms".format(sys.argv[0]))
print("start and ratio are floats, num_terms must be a nonnegative integer.")
exit(1)
try:
# If number of arguments (after script name) is not 3
# then this will generate ValueError
s_str, r_str, N_str = sys.argv[1:]
except ValueError:
print("Wrong number of arguments given.\n")
usage()
try:
s = float(s_str)
r = float(r_str)
N = int(N_str)
except ValueError:
print("Invalid argument type(s).\n")
usage()
if N<0:
print("num_terms must be nonnegative.\n")
usage()
try:
for i in range(N):
print(s*r**i)
except OverflowError:
print("Stopped calculation because an overflow occurred.")