Introduction to Python
davidbpython.com
In-Class Exercise Solutions, Session 8
PLEASE REFER to pythonreference.com for syntax to follow in coding these Exercises |
|
REVIEW: FUNCTION ARGUMENTS AND RETURN VALUES |
|
Ex. 8.1 | Write a function that takes two arguments and returns one value. |
Define function 'add' that takes two arguments for int values, adds them together and returns the sum. Note: you must not use 'a', 'b', 'x' or 'y' inside the function |
|
def add(arg1, arg2): # arg1: int, 5; arg2: int, 10 (first call below)
argsum = arg1 + arg2 # int, 15
return argsum # return 15
a = 5 # int, 5
b = 10 # int, 10
val1 = add(a, b) # int, 15
print(val1)
x = 10 # int, 10
y = 100 # int, 100
val2 = add(x, y) # int, 110
print(val2)
|
|
Ex. 8.2 | Write a function with one argument and one return value. |
Define function 'get_half' that takes one argument, divides the value by two, and returns the halved value. Note: you must not use 'a' or 'b' inside the function, and you must not print inside the function -- value must be returned. |
|
def get_half(val): # val: int, 5 (first call below)
hval = val / 2 # float, 2.5
return hval # return 2.5
a = 5 # int, 5
x = get_half(a) # float, 2.5
print(x)
b = 100 # int, 100
y = get_half(b) # float, 50.0
print(y)
|
|
Ex. 8.3 | Write a function with one argument and two return values. |
Define function 'double_and_halve' that takes one numeric argument, and returns the value doubled as well as halved. Note: you must not use 'a' or 'b' inside the function, and you must not print inside the function - values must be returned |
|
def double_and_halve(this): # this: int, 50
dthis = this * 2 # int, 100
hthis = this / 2 # float, 25.0
return dthis, hthis # return 100, 25.0
a = 50 # int, 50
d, h = double_and_halve(a) # int, 100; float 25.0
print(d) # 100
print(h) # 25.0
|
|
Ex. 8.4 | Write a function with two arguments and one return value. |
Define function 'get_sum' that takes two numeric arguments and returns the values summed. Note: you must not use 'x' or 'y' inside the function, and you must not print inside the function - value must be returned. |
|
def get_sum(a, b): # a: int, 50; b: int, 25
return a + b # return 75
x = 50 # int, 50
y = 25 # int, 25
z = get_sum(x, y) # int, 75
print(z)
|
|
LAB 1 |
|
Ex. 8.5 | Write a function with two arguments and one return value. |
Define function get_diff() that takes two numeric arguments and returns the difference between the two. Note: you must not use 'x' or 'y' inside the function, and you must not print inside the function - value must be returned. |
|
Suggested Solution:
def get_diff(a, b): # a: int, 50; b: int, 10
return a - b # int, 40
x = 50 # int, 50
y = 10 # int, 10
z = get_diff(x, y) # int, 40
print(z)
|
|
Ex. 8.6 | Write a function with two arguments and one return value. |
Define function get_quotient() that takes two numeric arguments, divides the first by the second, and returns the result. |
|
def get_quotient(arg1, arg2): # arg: int, 90; arg2: int, 10
quotarg = arg1 / arg2 # float, 9.0
return quotarg # return 9.0
aa = 90 # int, 90
bb = 10 # int, 10
c = get_quotient(aa, bb) # float, 9.0
print(c) # 9.0
|
|
Ex. 8.7 | Write a function with one argument and one return value. |
Define function get_lower() that takes a string argument and returns the value lowercased. |
|
def get_lower(val): # val: str, 'WELCOME TO THE WORLD.'
uval = val.lower() # str, 'welcome to the world.'
return uval
x = 'WELCOME TO THE WORLD.' # str, 'WELCOME TO THE WORLD.'
y = get_lower(x) # str, 'welcome to the world.'
print(y) # welcome to the world.
|
|
Ex. 8.8 | Write a function with one argument and one return value. |
Define function get_split() that takes a string argument for a comma-separated CSV string line and returns a list of values from the split. |
|
def get_split(this_line): # this_line: str, 'this,that,other'
items = this_line.split(',') # list, ['this', 'that', 'other']
return items # return ['this', 'that', 'other']
line = 'this,that,other' # str, 'this,that,other'
items = get_split(line) # list, ['this', 'that', 'other']
print(items) # ['this', 'that', 'other']
|
|
Ex. 8.9 | Write a function with one argument and one return value. |
Define function get_last_item() that takes a string argument for a comma-separated CSV string line and returns just the last comma-separated item from the line. |
|
def get_last_item(csv_line): # csv_line: str, '2017-09-03,Alpha Corp.'
items = csv_line.split(',') # list, ['2017-09-03', 'Alpha Corp.']
return items[-1] # return 'Alpha Corp.'
line = '2017-09-03,Alpha Corp.' # str, '2017-09-03,Alpha Corp.'
last = get_last_item(line) # str, 'Alpha Corp.'
print(last) # Alpha Corp.
|
|
Ex. 8.10 | Write a function that raises an exception. |
The function below should detect if an incorrect state name is passed to it, and raise a ValueError exception if it is. |
|
def get_tristate_pop(state): # state: str, 'ny' (first call below)
states = { 'ny': 19.45,
'nj': 8.88,
'ct': 3.57 } # dict
if state not in states: # bool, False
raise ValueError(f'state "{state}" not found')
return states[state] # return 19.45
popny = get_tristate_pop('ny') # float, 19.45
print(popny)
popca = get_tristate_pop('ca') # ValueError:
# state "ca" not found
print(popca)
|
|
FILE INSPECTIONS |
|
Ex. 8.11 | Show the present/current working directory. |
This is the one from which you are running your Python program. In most cases (but not always) it is the same as the location of the file you are running. Use os.getcwd(). Remember to import os. |
|
import os
cwd = os.getcwd() # str (your current directory)
print(cwd)
|
|
Ex. 8.12 | List a directory. |
Loop through the warmup_exercises/ directory list, printing each item. Use os.listdir(). |
|
import os
this_dir = '../warmup_exercises' # str, '../warmup_exercises'
items = os.listdir(this_dir)
for item in items: # str, 'warmup_exercise-01.txt' (sample)
print(item)
|
|
Ex. 8.13 | Build a filepath. |
Given the below directory name and filename, build a complete filepath. Use os.path.join() |
|
dirname = '../warmup_exercises/' # str, '../warmup_exercises/'
filename = 'warmup_1.1.py' # str, 'warmup_1.1.py'
filepath = os.path.join(dirname, filename) # str, '../warmup_exercises/warmup_1.1.py'
print(filepath)
|
|
Note that on Windows computers, os.path.join() will insert a backslash instead of a forward slash. This completed path is still valid. |
|
Ex. 8.14 | Check to see if an entry is a file. |
Given the below filename, confirm that the entry is a file by printing is a file!. Use os.path.isfile(). |
|
fname = '../pyku.txt' # str, '../pyku.txt'
if os.path.isfile(fname): # bool, True
print('is a file!')
|
|
Ex. 8.15 | Check to see if an entry is a directory. |
Given the below directory name, confirm the entry is a directory by printing is a directory!. Use os.path.isdir(). |
|
dirname = '../shakespeare' # str, '../shakespeare'
if os.path.isdir(dirname): # bool, True
print('is a directory!')
|
|
Ex. 8.16 | Get the size of a file. |
Given the below filepath, check the size of the file. Use os.path.getsize(). |
|
fname = '../pyku.txt' # str, '../pyku.txt'
bytesize = os.path.getsize(fname) # int, 80
print(bytesize)
|
|
Ex. 8.17 | (running from command line only) Read from sys.argv. |
Running the below code from the command line, print the value of sys.argv. Then, run the code again with the following 3 "words" on the same line when executing the script: greetings filesystem arguments. |
|
import sys
print(sys.argv) # list, ['inclass_exercise.txt', 'greetings', 'filesystem', 'arguments']
|
|
REVIEW: TRAPPING EXCEPTIONS -- TRY/EXCEPT |
|
Ex. 8.18 | Trap a "bad index" error. The below code takes user input and converts to int, then attempts to read the list item at that index value. A correct index (0-3) should allow you to print the value at that index. An incorrect index (>3) should raise an exception. Once you have observed this, use a 'try/except' statement to trap the exception and instead print 'no value at that index'. Make sure to put your 'try' block around just one line of code. |
x = ['a', 'b', 'c', 'd'] # list, ['a', 'b', 'c', 'd']
uidx = int(input('please enter an index: ')) # int, 99 (sample input)
try:
print(x[uidx]) # raises IndexError
except IndexError:
print('no value at that index')
|
|
Ex. 8.19 | Trap a "bad value" error. Since the input line also converts to int an input value that is not all digits should also raise an exception. Once you have observed this, use a 'try/except' statement to trap the exception and instead print 'numbers, only please'. Make sure to put your new 'try' block around just one line of code. Also, add an exit() to the except: block so the code doesn't continue executing past that line. (Note that in Jupyter Notebook you must use sys.exit() and that Jupyter will respond as if this is an error.) |
x = ['a', 'b', 'c', 'd'] # list, ['a', 'b', 'c', 'd']
try:
uidx = int(input('please enter an index: ')) # str, 'hey' (raises ValueError)
except ValueError:
print('numbers only, please')
try:
print(x[uidx])
except IndexError:
print('no value at that index')
|
|
Ex. 8.20 | Combine traps. Place the try: block around both the input line and the list index line. Now move your except: blocks so that they follow one another consecutively. Test the program both with a bad integer value and a bad index, to see that either exception can be handled. |
x = ['a', 'b', 'c', 'd'] # list, ['a', 'b', 'c', 'd']
try:
uidx = int(input('please enter an index: ')) # int, 9
print(x[uidx]) # raises IndexError
except ValueError:
print('numbers only, please')
except IndexError:
print('no value at that index')
|
|
Ex. 8.21 | Trap a "missing file" error. The below code attempts to open a file specified by the user's input. An existing filename should allow the program to show the length of the file in bytes. A non-existent filename should raise an exception. Once you have observed this, use a 'try/except' statement to trap the exception and instead print 'file does not exist'. Make sure to put your 'try' block around just one line. |
# existing filename: ../pyku.txt # str, '../pyku.txt'
import os
uifn = input("enter filename to see size in bytes: ")
# str, 'NotFile'
try:
print(f"this file's length is {os.path.getsize(uifn)}")
# raises FileNotFoundError
except FileNotFoundError:
print('file does not exist')
|
|
Ex. 8.22 | Trap a "bad directory" error. |
The below code attempts to list a directory specified by the user's input. An existing directory should allow the program to loop through the items in that directory. A non-existent directory should raise an exception. Once you have observed this, use a 'try/except' statement to trap the exception and instead print 'directory not found'. Make sure to put your 'try' block around just one line, and make sure to add an exit() to the end of the except: block so the program doesn't continue if the directory can't be found. (Note that in Jupyter Notebook you must use sys.exit() and that Jupyter will respond as if this is an error.) Test for both correct directory (shown at top) and incorrect directory. |
|
# existing directory name: ../shakespeare
import os
uidn = input("name of directory to list: ") # str, 'somebaddir'
uidpath = os.path.join('..', uidn) # str, '../somebaddir'
try:
items = os.listdir(uidpath) # raises FileNotFoundError
except FileNotFoundError:
print('directory not found')
exit()
for item in items:
print(item)
|
|
Ex. 8.23 | Command line only: Identify error type and trap exception for missing command line argument. |
Suppose that the user has provided arguments at the command line resulting in sys.argv having the list values, as shown:
command line argument: 1927 sys.argv value: ['inclass_X.X.py', '1927'] |
|
The program currently reads and prints the 1st command line argument ('1927', i.e. 2nd item of the list). Now run the program without any argument and see what exception results. Then use a try/except to trap the error if it occurs. If it does, print 'please enter an argument'. |
|
import sys
arg = sys.argv[1] # str, '1927'
print('argument is {arg}')
|
|
LAB 2 |
|
Ex. 8.24 | List a directory and show full path to each file. |
Starting with the below directory, list the directory's contents, joining each entry to the directory name so it becomes a full path to the directory. |
|
import os
dirname = '../testdir' # str, '../testdir'
items = os.listdir(dirname)
for entry in items: # str, 'file1.txt'
fpath = os.path.join(dirname, entry) # str, '../testdir/file1.txt'
print(fpath)
|
|
Note that your results may be in a different order on your system. Also, you may see additional entries .DS_Store, .Trashes or other "hidden" files starting with a period. |
|
Ex. 8.25 | List a directory and show file sizes. |
Extend the previous solution by printing the file size of each file or directory. Use a comma between varaible names to print two values on the same line, e.g. print(this, that). |
|
import os
dirname = '../testdir' # str, '../testdir'
entries = os.listdir(dirname)
for name in entries: # str, 'file1.txt' (sample first file)
fpath = os.path.join(dirname, name) # str, '../testdir/file1.tsxt'
fsize = os.path.getsize(fpath) # int, 33
print(fpath, fsize)
|
|
Ex. 8.26 | List a directory and identify file or directory. |
Modify the previous solution so that the program identifies each listing as either a file or directory. |
|
import os
dirname = '../testdir' # str, '../testdir'
items = os.listdir(dirname)
for name in items: # str, 'file1.txt' (sample first file)
fpath = os.path.join(dirname, name) # str, '../testdir/file1.txt'
if os.path.isdir(fpath): # bool, False
print(f'{fpath}: dir')
elif is.path.isfile(fpath): # bool, True
print(f'{fpath}: fpath')
|
|
Ex. 8.27 | See if a file exists as a file; if not, show present working directory. |
Take input for a filepath; check to see if the file exists. If not, show the present working directory. |
|
import os
filename = input('please enter a filename: ') # str, 'thisfile.txt'
# could also use os.path.isfile()
if os.path.exists(filename): # bool, True
cwd = os.getcwd() # str, '/Users/yourname' (sample dir)
print(f'"filename" does not exist. Present working directory is {cwd}')
|
|
If the file can't be opened, we should see a message like this one:
Error: "thisfile.txt" does not exist. Present working directory is# /Users/david/Downloads/session_08_files_dirs_stdout/inclass_exercises# |
|
Ex. 8.28 | A function to generate a file listing. |
Write a function get_listing() that takes a directory name and returns the list of entries in that directory. If the directory name is not a valid directory, have the function raise a NotADirectoryError exception. |
|
import os
def get_listing(dirname): # dirname: str, '.'
if not os.path.isdir(dirname): # bool, False
raise NotADirectoryError(f'directory "{dirname}" could not be opened')
items = os.listdir(dirname)
return items
# this should succeed
listing = get_listing('.') # list, (files and dirs in this dir)
print(listing)
print()
# this should raise NotADirectoryError exception
listing = get_listing('wrong') # raises NotADirectoryError
|
|
Ex. 8.29 | A function to process command line arguments (test from command line only). |
Write a function get_args() that reads from sys.argv and returns the 2nd through last items in the sys.argv list (i.e., a slice omitting the first item). If no arguments are passed at the command line, the function will return an empty list. |
|
For the below solution, assume the args this that other
import sys
def get_args():
arguments = sys.argv[1:] # list, ['this', 'that', 'other']
return arguments
args = get_args() # list, ['this', 'that', 'other']
print(args)
|
|
You must of course run this program from the command line and pass arguments at the command line to see this program work properly. |
|
Ex. 8.30 | Raise an exception if input is correct. (test from command line only) |
Extend the previous solution to accept a 2nd argument, an integer. The integer will specify how many arguments should be in sys.argv (not counting the initial filename argument of course). If there are not the indicated number of arguments, the function will raise a ValueError exception. |
|
import sys
def get_args(size): # size: int, 2
arguments = sys.argv[1:] # ['this', 'that']
if len(arguments) != size: # bool, False
raise ValueError(f'must pass {size} cmd args') #
return arguments # return ['this', 'that']
# expecting command line arguments this that
args = get_args(2) # list, ['this', 'that']
|
|
Expected Output:
# if no arguments are passed
args = get_args(2) # ValueError('must pass 2 cmd args')
# if two arguments are passed
args = get_args(2) # list, ['val1, 'val2']
|
|
WRITING TO FILES |
|
Ex. 8.31 | Write to a file. Open a file for writing (using a new filename such as newfile.txt and the additional argument 'w') and write some text to it (using the file .write() method. After running the program/cell, open the file and look at it to see it has been written to (make sure to call .close() on the file or you may not see the written text.) |
wfh = open('newfile.txt', 'w') # 'file' object
wfh.write('here is some text') # int, 17
wfh.close()
|
|
Ex. 8.32 | Write lines to a file, including newlines. Open a file for writing (using a new filename) and write 3 lines to it (they can be as simple as 'line1', 'line2' and 'line3'. Add the newline character to each line. After running the program/cell, open the file and look at it to see it has been written to (make sure to call .close() on the file or you may not see the written text.) |
wfh = open('newfile.txt', 'w') # 'file' object
wfh.write('here is some text\n') # int, 18
wfh.write('here is some more text\n') # int, 23
wfh.write('here is some more...\n') # int, 21
wfh.close()
|
|
Ex. 8.33 | Append to an existing file. Open the file you created previously for appending (using the 'a' argument instead of 'w') and write one or more additional lines to it. Again, add the newline character to each line. After running the program/cell, open the file and look at it to see it has been written to (make sure to call .close() on the file or you may not see the written text.) |
afh = open('newfile.txt', 'a') # 'file' object
afh.write('THIS IS ONE MORE LINE...\n') # int, 25
afh.close()
|
|