In [ ]:
gal_to_litre = 3.78541178
mile_to_km = 1.609344
def convert_mileage(mpg):
'''Converts miles per gallon to liters per 100 km'''
litres_per_100_km = 100 / mpg / mile_to_km * gal_to_litre
return litres_per_100_km
Create a subdirectory in your version control directory called testing-exercises, then
copy this function into a file in that directory called mileage.py. Add more
code to that file to repeatedly ask the user for a mileage in miles per gallon,
and output the mileage in liters per 100 km, until the user enters the string
q. You will need to use the float() function to convert from string to a
floating point number. Use the 'if __name__ == "__main__":' trick to ensure
that the module can be imported without executing your testing code.
Copy mileage.py to create tryexcept.py Add a try/except block to the new
program to display a helpful message instead of crashing when users enter
invalid input (such as the number "0" or the name of their favorite hockey
team).
Reading the function again, you realize that accepting 0 or negative values
make no sense and should be reported as an error. Look at the exceptions defined
in the exceptions module (see the online documentation or use the built-in help(...) or dir(...)
functions) and decide which of Python's built-in exceptions is most appropriate
to use for invalid input. Create a copy of 'tryexcept.py' called 'raiser.py'
that raises this exception; modify the main body of your program to catch it;
and add a comment inside the file explaining why you chose the exception you
did. (Note: you have to call this file raiser.py, not raise.py because
'import raise' is an error. Can you see why?)
According to Google,
20 miles per gallon are equivalent to 11.7607292 liters per 100 km. Use these
values to write a unit test. Keep in mind that these floating values are subject
to truncation and rounding errors. Save the test case in a file called
test_mileage.py and run it using the nosetests command. Note:
test_mileage.py should use 'from raiser import convert_mileage' to get the
final version of your mileage conversion function.
Now add a second test case, for 40 miles per gallon equivalent to 5.88036458 liters per 100 km and run the tests again. Unless you have already fixed the error that was present in the initial function, your test should fail. Find and fix the error; submit your new function in a file called 'final_mileage.py'.
The results of a set of experiments are stored in a file, where the i-th line stores the results of the i-th experiment as a comma-separated list of integers. A student is assigned the task of finding the experiment with the smallest average value. She writes the following code:
In [ ]:
def avg_line(line):
values = line.split(',')
count = 0
total = 0
for value in values:
total += int(value)
count += 1
return total / count
def min_avg(file_name):
contents = open(file_name)
averages = []
for (i, line) in enumerate(contents):
averages.append((avg_line(line), i))
contents.close()
averages.sort()
min_avg, experiment_number = averages[0]
return experiment_number
Refactor min_avg so that it can be tested without depending on external
files. Submit your code in a file called first_averages.py.
Write Nose test cases for both functions. Consider what should happen if the
file is empty. Submit your tests in a file called test_first_averages.py.
Note: you may assume for now that all input is well formatted, i.e., you do
not have to worry about empty lines, lines containing the names of hockey
teams, etc.
The given specification is ambiguous: what should the result be if two or more experiments are tied for the minimum average? Copy 'first_averages.py' to create a new file 'second_averages.py'; modify it to handle this case; add a comment to the top explaining what rule you decided to use; and create a file 'test_second_averages.py' that tests your changes.
Another student proposed an alternative implementation of the min_avg function:
In [ ]:
def min_avg(file_name):
contents = open(file_name).readlines()
min_avg = avg_line(contents[0])
min_index = 0
for (i,line) in enumerate(contents):
current_avg = avg_line(line)
if current_avg <= min_avg:
min_avg = current_avg
min_index = i
return min_index
This implementation also finds an experiment with the smallest average, but possibly a different one than the your function. Modify your test cases so that both your implementation and this one will pass. (Hint: use the 'in' operator.)