Course 2.1Lesson 5 of 5
In this project we write a safe data reader. Lines of the form name,mark come in from a messy source, with a mark in words, a missing mark, a mark out of range and an empty line. The program keeps the good lines in a dictionary, and reports each bad line with its line number and the reason, instead of stopping. We plan the cases and the expected result by hand, build the reader with try, except and a raised error, test the average of the good data and the list of problems, and extend the reader with a count of the kinds of problem and a limit on the number of problems.
Try the code and the simulations beside the lesson.
After this lesson you can
try, except, raise and continue in one loop, andData from the real world is messy. A teacher types the marks of a class into a file, one line for each student, in the form name,mark. But people make mistakes: a mark in words, a missing mark, a mark of 140, an empty line. A program that stops at the first bad line is no use. A program that skips the bad lines silently is worse, because the teacher does not know that anything went wrong.
We want a reader that
name: mark,The lines are:
| Line | Text | Verdict |
|---|---|---|
| 1 | Asha,72 | good |
| 2 | Ravi,85 | good |
| 3 | Meera,sixty | bad: the mark is not a whole number |
| 4 | Kabir | bad: no comma, so the line does not split into two |
| 5 | Ana,140 | bad: out of range |
| 6 | Dev,-3 | bad: out of range |
| 7 | Tara,90 | good |
| 8 | (empty) | bad: no comma |
The expected result: five problems, the lines 3, 4, 5, 6 and 8. The good dictionary has Asha 72, Ravi 85 and Tara 90. The average is 247 divided by 3, which is about 82.33.
The messages from Python itself (invalid literal for int() with base 10: 'sixty') are a little technical, but they say what happened. A tidier reader could write its own sentence for each case, with raise ValueError("the mark is not a number").
Use the table as your test. All eight lines have a known verdict. Then test the edges.
| Test | Expected |
|---|---|
| a mark of exactly 0 | good |
| a mark of exactly 100 | good |
| a mark of 101 | bad |
a name with spaces, such as Mary Ann,80 | good (the split is at the comma only) |
two commas, Ravi,85,90 | bad |
spaces around the number, Ravi, 85 | good: int(" 85") works |
| no good line at all | the average would divide by zero |
The last row is a real fault in the program: if every line is bad, good is empty, and sum(...) / len(good) stops with a ZeroDivisionError. A safe reader must check if good: before the average.
The if good: at the end is the check that the reader needs when every line is bad.
Pick one or two, and do them without looking at a solution. Write the expected answers first.
No good lines instead of dividing by zero.read_marks(lines) that returns the dictionary and the list of problems as a tuple.good[name] = mark inside the try. Then you do not know which line failed.continue. The bad line is added with an old value of mark.except:. A typing mistake in the reader is hidden.len(good) with no good lines.Start with two quick questions. Each New numbers gives you a fresh one, so you can practise as long as you like.
Then the labs and the problems:
try around the risky lines, one except for the kinds that you expect, continue to go on.Try each one on your own first. If you are stuck, open a hint. Then check with Show the answer.
Kabir (with no comma) a problem?good[name] = mark come after the try block?Every lesson is open to read. Enrolling also lets you:
Log in to join the discussion.
Loading…
This lesson is free to read. Enroll free to keep your place and take the tests.