Final Exam Model Paper 7
Theory paper: 50 marksTime: 2 hours
Practical exam: 25 marksTime: 1 hour 30 minutes
All questions are compulsory.
A full practice run of the Grade 10 final exam: the theory paper (50 marks, 2 hours) and, below it, the practical exam (25 marks, 1 hour 30 minutes, at a computer, marked by the school). In the theory paper, work out on paper what each program does, as in the exam hall: its programs have no Run button. In the practical exam, the programs run on this page.
A practice paper by Science Playground, made to its own course’s grid; not an official exam paper.
Write your answers on paper first. Then open each answer and its marking scheme, and give yourself one mark for each point you got. In multiple choice, your first choice counts.
Section A
10 × 1 = 101. Choose the correct option for each of the following questions.
A weather API sends JSON text in which one field is "rain": null. After json.loads(), what is that field’s value in Python?
Pick an answer to see why.
The folders on an agriculture office’s computer in Pyuthan, as a dictionary of each folder’s contents:
folders = { "farm-data": ["crops", "livestock", "readme.txt"], "crops": ["rice.csv", "maize.csv", "old"], "livestock": ["goats.csv"], "old": [],}Seen as a tree with farm-data at its root, how many leaves does it have?
Pick an answer to see why.
Each member of a farmers’ cooperative has a 10-digit member number. Its last digit is worked out from the other nine, so that the computer can catch most mistyped numbers. What is that last digit called?
Pick an answer to see why.
A chart from a climate data set shows that a district in the hills gets about 1,700 mm of rain a year, averaged over 1981 to 2010. Bishnu, a farmer there, says: “So my field will get 1,700 mm next year, and I can plan my rice by it.” Which judgment is right?
Pick an answer to see why.
An app shows a map picture 1,000 pixels wide. Its left edge is at longitude 83.80° E and its right edge at 83.90° E. A farm is at longitude 83.83° E. How many pixels from the left edge does the app draw it?
Pick an answer to see why.
What is an administrator account on a computer?
Pick an answer to see why.
What is a language model’s vocabulary?
Pick an answer to see why.
In John Searle’s Chinese room, a man who knows no Chinese sits in a room with a rule book. Following its rules, he answers notes written in Chinese so well that people outside think someone in the room understands Chinese. What is the story meant to show?
Pick an answer to see why.
Until 2018, all of Nepal’s fiber links to the rest of the world came through India; in January 2018 a link through China opened at Rasuwagadhi. In which year would cutting every link through India have cut Nepal’s internet off from the rest of the world?
Pick an answer to see why.
Sanjay, in Grade 10 in Nawalparasi, writes his plan: “I will be a software developer. Next step: learn programming some day.” Which judgment of his plan is best?
Pick an answer to see why.
Section B
10 × 2 = 20Write short answers to the following questions.
A cooperative in Syangja finds its biggest orange harvest:
harvest = {"Hari": 420, "Sita": 380, "Maya": 510} # kgmax = 0for name in harvest: if harvest[name] > max: max = harvest[name]print("Biggest:", max)print("Check:", max(harvest.values()))- i.What does line 6 print?
- ii.Line 7 stops the program with
TypeError: 'int' object is not callable. Why? How should the program be changed?
Answer
i. The loop keeps the biggest value seen so far: 420, then 510.
Output
Biggest: 510ii. max is a built-in function, but line 2 made a variable called max that shadows it: from then on, the name max means the number 510, and a number can’t be called like a function. Give the variable another name, such as biggest, in lines 2, 5 and 6; then line 7’s max() is the built-in again and prints Check: 510.
Marking scheme
- i.
Biggest: 510. - ii. The variable max shadows the built-in max(), so line 7 calls a number; rename the variable (e.g. biggest).
Foot-and-mouth disease is found among the cattle of one farm in Salyan. It spreads between farms whose cattle graze on the same pasture. The livestock office keeps, for every pasture, the farms that use it, and wants a program that lists the farms the disease could reach in one or two jumps, to vaccinate the nearest first. Design it: what are the nodes and the edges (one way or both ways?), and which search answers the question, remembering what?
Answer
- Nodes: the farms. Edges: join two farms that share a pasture; they go both ways (sharing is mutual), so each edge is written in both farms’ lists when the graph is built from the pasture lists.
- Search: a breadth-first search from the sick farm, keeping each farm’s steps in a dictionary. It finds the farms in rings: steps 1 (sharing a pasture with the sick farm, vaccinate first), then steps 2. List the farms with steps 1 or 2, nearest first.
Marking scheme
- Nodes are farms; edges join farms that share a pasture, both ways.
- Breadth-first search from the sick farm, keeping the steps; list farms 1 then 2 steps away.
A vegetable cooperative records its sales in a table, sales:
| sale_id | farmer | crop | kg | day |
|---|---|---|---|---|
| … | … | … | … | … |
| 56 | Bimala Magar | cardamom | 12 | 2026-10-04 |
| 57 | Bimala Magar | cardamom | 12 | 2026-10-04 |
| … | … | … | … | … |
The same sale was typed twice: row 57 is the copy. Write the SQL statement that removes only that row, and the statement the manager should run first. Why should she pick the row by its sale_id, not by the farmer, crop and day?
Answer
First check exactly which rows the condition picks, then delete with the same WHERE:
SELECT * FROM sales WHERE sale_id = 57;DELETE FROM sales WHERE sale_id = 57;The farmer, crop, kg and day are the same in rows 56 and 57, so a WHERE on them would delete both, the real sale too. sale_id is the primary key, different in every row, so it picks exactly one.
Marking scheme
DELETE FROM sales WHERE sale_id = 57;with aSELECT … WHERE sale_id = 57run first to see what it picks.- The other fields match both rows (both would be deleted); the primary key picks only one.
Three dairy cooperatives in Chitwan record the milk they collect each month in milk.csv (month, cooperative, liters). Ratnanagar’s is about 3,000 liters a month, Kalika’s about 300. A program draws them:
import pandas as pdimport matplotlib.pyplot as plt milk = pd.read_csv("milk.csv")fig, axes = plt.subplots(1, 3, sharex=True, sharey=True, figsize=(9, 3)) for ax, coop in zip(axes, ["Ratnanagar", "Khairahani", "Kalika"]): group = milk[milk["cooperative"] == coop] ax.plot(group["month"], group["liters"], marker="o") ax.set_title(coop) axes[0].set_ylabel("Milk (liters)")plt.show()- i.What does line 5 make, and what does each turn of the loop draw?
- ii.Why do these charts need
sharex=True, sharey=True? What would they seem to say without them?
Answer
- i.Line 5 makes one row of three charts side by side,
axes: small multiples. Each turn of the loop picks one cooperative’s rows and draws its milk month by month, as a line with dots, in its own chart, with the cooperative’s name as the title. - ii.So that all three charts have the same scales: a point at the same height means the same number of liters in each. Without them, each chart would stretch its own axis to fit its own numbers, so Kalika’s line, about 300 liters, would fill its chart just as Ratnanagar’s 3,000 fills its own, and the three cooperatives would look about the same size.
Marking scheme
- i. One row of three charts (small multiples); each turn draws one cooperative’s milk by month, titled with its name.
- ii. Shared scales make the same height mean the same liters; without them Kalika would look as big as Ratnanagar.
The printer in a cooperative’s office stopped printing. Prakash changed three things at once: he put in a new cable, installed a new driver, and chose another default printer. Now it prints.
- i.What is wrong with fixing it this way?
- ii.How should he have done it?
Answer
- i.He doesn’t know which change fixed it, so if it happens again he won’t know what to do; and the two changes that weren’t needed may have broken something else that will show up later (the new driver, for example).
- ii.Change one thing at a time, and test after each. If a change doesn’t help, undo it before trying the next, and keep a short note of what he tried and what happened.
Marking scheme
- i. He can’t tell which change fixed it, and the other changes may cause new problems.
- ii. One change at a time, test after each, undo what didn’t help (and keep a note).
Ramila’s program for a rice mill:
WEIGHT = 50 # kg in a bag of ricetotal = 0bags = input("Bags of rice? ")total = total + bags * WEIGHTprint("Total:", total, "kg")She types 12, and gets:
Error message
Traceback (most recent call last): File "main.py", line 4, in <module> total = total + bags * WEIGHT ~~~~~~^~~~~~~~~~~~~~~TypeError: unsupported operand type(s) for +: 'int' and 'str'- i.Which line failed, and what kind of error is it? Explain the message.
- ii.Write the change that fixes the program.
Answer
- i.Line 4, a TypeError:
+was given an int (total, 0) and a str, and Python can’t add a number to text. The text came frominput(), which always gives a string: “12” × 50 is not 600, it is the text “12” repeated 50 times, so the multiplication worked and the addition failed. - ii.Turn the answer into a number when it is read:
bags = int(input("Bags of rice? ")). Then the program printsTotal: 600 kg.
Marking scheme
- i. Line 4, TypeError: an int and a str can’t be added, because input() gives text.
- ii.
bags = int(input(…))(orint(bags)in line 4).
Rojina asks a chatbot, three times in new chats, “How high is Kanchenjunga?” Twice it says 8,586 m, and once 8,598 m.
- i.Explain, from how the model picks each token, why the answers differ.
- ii.Her friend says: “Ask five times and take the most common answer: then it is checked.” Why isn’t that a real check?
Answer
- i.At every token the model has chances for many next tokens, and with a temperature above 0 it picks at random, weighted by those chances. The digits of a number are tokens too, so now and then a less likely digit is picked, and the answer changes; once a wrong digit is written, the rest of the answer goes on from it.
- ii.All five answers come from the same model and the same training text. If a wrong number was common in that text, the most common answer can be wrong too. Asking again only shows what the model finds likely, not what is true. A real check is a reliable source: here, 8,586 m is the height given by the Survey Department and in atlases.
Marking scheme
- i. It picks each token at random, weighted by the chances (temperature above 0), and digits are tokens, so a less likely digit is sometimes picked.
- ii. The answers all come from the same model and text, so the commonest can still be wrong; check a reliable source.
A company’s app looks at a photo of a leaf and names the crop disease. Its makers tested it on 2,000 photos of rice and maize leaves, all taken in Chitwan in the summer, and it named 95% correctly. An apple growers’ group in Jumla wants to use it in its orchards. Judge whether the 95% tells them how well it will work for them, and say what they should do.
Answer
It doesn’t. A test score only says how the model does on things like its test set, and their apple leaves, apple diseases, mountain light and winter photos were not in it: the model may be much worse on them, and one total can hide a group where it is weak. The group should ask for (or make) a test set of their own photos, with the diseases checked by an expert, count the accuracy for apples separately, and judge the harm of each kind of mistake (a disease missed can cost a season’s crop) before relying on it.
Marking scheme
- The 95% holds only for photos like the test set (rice and maize, Chitwan, summer); apples in Jumla were not tested, so it may be much worse.
- Test it on their own checked photos, counting apples separately, and weigh the harm of its mistakes.
Every technology is the result of four kinds of choices. Name them, and give an example of any two.
Answer
The choices of how to design it, whether to use it, where to deploy it (put it into service), and how to regulate it (what rules to make). Examples: design, storing a year in two digits to save memory (the Year 2000 problem); use, whether a shop takes cash or only digital payments; deploy, which towns get a new mobile tower first; regulate, a rule with a review clause or a sandbox for a new payment service.
Marking scheme
- The four: design, use, deploy, regulate.
- An example of any two of them.
A cooperative in Gulmi has typed its members’ records in the Preeti font for twenty years. The secretary says: “Everyone in the office knows Preeti, so we will keep using it.” Judge this choice.
Answer
It is a choice that will cost more the longer it lasts. Preeti stores Devanagari as the codes of English letters, so on any computer or phone without that font, and in today’s programs, the records turn into gibberish; they can’t be searched or sorted properly in Nepali, sent to a bank or a government office, or read in twenty years. Each year adds more documents to convert. A better choice is to type new records in Unicode Nepali now, and convert the old ones, keeping the originals until the copies are checked.
Marking scheme
- Preeti stores letters’ codes, so the records become gibberish without the font, and can’t be searched or shared; the cost grows with every year.
- A better plan: Unicode for new records, and convert the old ones (checking the copies).
Section C
5 × 4 = 20Write long answers to the following questions.
At an orange collection center in Syangja, oranges are graded: grade A is bought at Rs 80 a kg, grade B at Rs 60 and grade C at Rs 35. Each farmer’s oranges are weighed by grade, and the farmer is given a slip with the total kg and the amount.
- i.Break the job “weigh, pay and give each farmer a slip” into three functions, top-down, and say which of them should be pure. (1)
- ii.Write a module, oranges.py, with the prices as a constant and a function
payment(kg_by_grade)with a docstring, which takes a dictionary such as{"A": 40, "B": 25, "C": 10}and returns the total kg and the amount. (2) - iii.Why should
paymentreturn the two numbers, rather than print the slip itself? (1)
Answer
i. For example: read_weights() asks for the kg of each grade (input, a side effect); payment(kg_by_grade) works out the total kg and the amount; print_slip(name, total_kg, amount) prints the slip (a side effect). payment should be pure: it only takes the weights in and gives the numbers back.
ii.
oranges.py
"""Paying farmers at the orange collection center.""" PRICES = {"A": 80, "B": 60, "C": 35} # rupees a kg, by grade def payment(kg_by_grade): """Given the kg of each grade, as a dictionary, return the total kg and the amount to pay in rupees.""" total_kg = 0 amount = 0 for grade in kg_by_grade: total_kg = total_kg + kg_by_grade[grade] amount = amount + kg_by_grade[grade] * PRICES[grade] return total_kg, amount if __name__ == "__main__": print(payment({"A": 40, "B": 25, "C": 10}), "should be (75, 5050)")40 × 80 + 25 × 60 + 10 × 35 = 3,200 + 1,500 + 350 = Rs 5,050, for 75 kg.
iii. A returned value can be used: printed on a slip today, but also added to the day’s totals, saved in the cooperative’s records or shown in an app, and it can be tested by checking the numbers. A function that printed would decide for every caller what to do with them.
Marking scheme
- i. Three sensible functions (read, work out, print), with the one that works out the payment pure.
- ii. A function that adds up the kg and the amount from the dictionary, using the prices as a constant (a dictionary of grades).
- ii. It returns both numbers (a tuple) and has a docstring.
- iii. Returning lets callers use and test the numbers (totals, saving, an app); printing decides for them.
Water flows one way through the canals of a farmers’ irrigation scheme in Dang, from the intake on the river. The dictionary lists, for each place, the places its canals carry water to:
canals = { "Intake": ["Main canal"], "Main canal": ["Upper branch", "Lower branch"], "Upper branch": ["Field 1", "Field 2"], "Lower branch": ["Field 3", "Pond"], "Field 1": ["Field 4"], "Field 2": [], "Field 3": ["Field 5"], "Pond": ["Field 5"], "Field 4": [], "Field 5": ["Field 6"], "Field 6": [], "Field 7": ["Field 6"],}- i.Do a breadth-first search from the Intake by hand, following the canals only the way water flows. Write a row for each visit: the place visited, its steps, the new places added (with their steps), and the list still to visit. (2)
- ii.Through how few canals does water reach Field 6? Write the route. (1)
- iii.Field 7 is in the dictionary, and a canal joins it to Field 6, yet the search never reaches it. Why? (1)
Answer
i.
| Visit | Steps | New places (steps) | List still to visit, front first |
|---|---|---|---|
| (start) | Intake (0) | Intake | |
| Intake | 0 | Main canal (1) | Main canal |
| Main canal | 1 | Upper branch, Lower branch (2) | Upper branch, Lower branch |
| Upper branch | 2 | Field 1, Field 2 (3) | Lower branch, Field 1, Field 2 |
| Lower branch | 2 | Field 3, Pond (3) | Field 1, Field 2, Field 3, Pond |
| Field 1 | 3 | Field 4 (4) | Field 2, Field 3, Pond, Field 4 |
| Field 2 | 3 | none | Field 3, Pond, Field 4 |
| Field 3 | 3 | Field 5 (4) | Pond, Field 4, Field 5 |
| Pond | 3 | none (Field 5 already seen) | Field 4, Field 5 |
| Field 4 | 4 | none | Field 5 |
| Field 5 | 4 | Field 6 (5) | Field 6 |
| Field 6 | 5 | none | (empty) |
- ii.5 canals: Field 6 was first reached from Field 5, Field 5 from Field 3, Field 3 from the Lower branch, the Lower branch from the Main canal, and that from the Intake: Intake → Main canal → Lower branch → Field 3 → Field 5 → Field 6.
- iii.The graph is directed: the canal runs from Field 7 to Field 6, so water (and the search, which follows the arrows only forwards) can’t go up it from Field 6. No place’s list contains Field 7, so nothing leads to it and it gets no water from the intake.
Marking scheme
- i. The visits in the right order: Intake; Main canal; Upper branch, Lower branch; Field 1, Field 2, Field 3, Pond; Field 4, Field 5; Field 6.
- i. Correct steps (1 to 5 as above), with the list as a queue and Field 5 not added twice.
- ii. 5 canals, Intake → Main canal → Lower branch → Field 3 → Field 5 → Field 6.
- iii. The canal goes one way, from Field 7 to Field 6 (a directed graph), and no list has Field 7, so it can’t be reached.
A spice and fruit cooperative in Myagdi keeps its farmers and their sales in two tables.
farmers
| farmer_id | name | ward |
|---|---|---|
| 1 | Dil Bahadur Thapa | 2 |
| 2 | Kamala Rana | 5 |
| 3 | Bishnu Pun | 2 |
| 4 | Gita Gurung | 7 |
sales
| sale_id | farmer_id | crop | kg | price_per_kg |
|---|---|---|---|---|
| 1 | 1 | ginger | 120 | 95 |
| 2 | 2 | orange | 300 | 60 |
| 3 | 3 | ginger | 80 | 100 |
| 4 | 1 | orange | 150 | 55 |
| 5 | 4 | cardamom | 20 | 1800 |
| 6 | 2 | ginger | 60 | 90 |
| 7 | 3 | orange | 210 | 65 |
Write what each query gives.
- i.
SELECT sale_id, crop, kg FROM sales ORDER BY kg DESC LIMIT 2;(1) - ii.
SELECT crop, AVG(price_per_kg) FROM sales GROUP BY crop ORDER BY crop;(1) - iii.(1)
SELECT farmers.name, sales.kgFROM salesJOIN farmers ON sales.farmer_id = farmers.farmer_idWHERE sales.crop = 'ginger' AND farmers.ward = 2ORDER BY sales.kg DESC;iv. SELECT sale_id, crop, kg FROM sales WHERE crop IN ('ginger', 'cardamom') AND kg < 100 ORDER BY kg; (1)
Answer
i. The two biggest sales, by kg:
| sale_id | crop | kg |
|---|---|---|
| 2 | orange | 300 |
| 7 | orange | 210 |
ii. One row per crop, with the average of its prices: ginger (95 + 100 + 90) ÷ 3 = 95, orange (60 + 55 + 65) ÷ 3 = 60.
| crop | AVG(price_per_kg) |
|---|---|
| cardamom | 1800.0 |
| ginger | 95.0 |
| orange | 60.0 |
iii. The ginger sales of farmers in ward 2, each joined to its farmer’s row, the most first (Kamala Rana sold ginger too, but she is in ward 5):
| name | kg |
|---|---|
| Dil Bahadur Thapa | 120 |
| Bishnu Pun | 80 |
iv. The ginger and cardamom sales of under 100 kg, the smallest first (sale 1, of 120 kg, is left out):
| sale_id | crop | kg |
|---|---|---|
| 5 | cardamom | 20 |
| 6 | ginger | 60 |
| 3 | ginger | 80 |
Marking scheme
- i. Sales 2 (orange, 300) and 7 (orange, 210).
- ii. cardamom 1800, ginger 95, orange 60.
- iii. Dil Bahadur Thapa 120, then Bishnu Pun 80.
- iv. Sales 5 (20), 6 (60) and 3 (80), in that order.
An agriculture office has a row for each of a few farms in farms.csv: its district, its land in ropani and its harvest of vegetables in kg in one year. It draws a chart:
farms.csv
district,land,harvestKaski,4,1900Kaski,20,8800Kaski,150,52000Dhading,3,900Dhading,25,6100Dhading,300,61000Syangja,2,700Syangja,40,12500Syangja,120,30000import pandas as pdimport matplotlib.pyplot as plt farms = pd.read_csv("farms.csv")colors = {"Kaski": "green", "Dhading": "blue", "Syangja": "orange"} for district, group in farms.groupby("district"): plt.scatter(group["land"], group["harvest"], color=colors[district], label=district) plt.xscale("log")plt.yscale("log")plt.xlabel("Land (ropani, log scale)")plt.ylabel("Harvest (kg a year, log scale)")plt.legend()plt.show()- i.What does each dot show, and what does its color show? How many variables does the chart show? (1)
- ii.What does
farms.groupby("district")give the loop in line 7, and why does the chart need a legend? (1) - iii.Why do lines 10 and 11 make both axes log scales, and why must the labels say so? (1)
- iv.On the chart, Kaski’s dots lie above Dhading’s at the same land. Write one honest sentence about what this shows, and one thing it doesn’t show. (1)
Answer
- i.Each dot is one farm: across, its land; up, its harvest. The color shows its district. So the chart shows three variables at once (a multivariate chart).
- ii.Each district’s name with its group of rows, one district at a time, so each district is drawn in its own color with its own label. The legend is the key that says which color is which district; without it the colors mean nothing.
- iii.The farms run from 2 to 300 ropani, and the harvests from 700 to 61,000 kg: several powers of ten. On ordinary scales the big farms would sit at the far corner and the small ones would be squashed together near 0. On a log scale each step is ten times the one before, so small and big farms all get room. A reader must be told, or they will think the gaps are equal.
- iv.Shows: in these few farms, Kaski’s farms harvested more for the same land than Dhading’s. Doesn’t show: why (irrigation, soil or the crops grown could explain it), or that it holds for all farms in the districts: there are only three farms from each, so it could be chance.
Marking scheme
- i. A dot per farm, land across and harvest up, color the district: three variables.
- ii. groupby gives each district’s name with its rows, so each is drawn in its own color and label; the legend says which color is which.
- iii. The numbers run over several powers of ten, so a log scale gives the small ones room; it must be named or readers think the gaps are equal.
- iv. An honest sentence (in these farms, Kaski’s harvest more for the same land), and a limit: not the cause, or too few farms to be sure.
Read the given passage and answer the questions that follow.
A cooperative in Marpha, Mustang, keeps its apples in a cold store. A small device reads the temperature inside every 30 minutes and adds one line to a CSV file: the date and time, and the temperature in °C. Each evening the file is sent to the manager’s phone, which draws it as a line chart. One night the power was cut, and no readings were saved from 01:00 to 03:00.
- i.What is this kind of keeping of readings called, and what is the file called? (1)
- ii.Why must every reading carry its date and time? (1)
- iii.Why is a CSV file a good form for the readings? (1)
- iv.How should the chart show the hours from 01:00 to 03:00, and why? (1)
Answer
- i.Keeping readings, each with its time, is logging, and the file of readings is a data log.
- ii.So that the manager knows when each reading was taken: to see how the temperature changes through the night and day, to find when something went wrong (and match it to the power cut), and to see which readings are missing.
- iii.It is plain text, one line per reading, with the values separated by commas, so the device can simply add a line each time, and almost any program (a spreadsheet, pandas) can read it.
- iv.As a gap: the line should break, or show only the points, with nothing between 01:00 and 03:00. A line drawn straight across would look like a measurement of temperatures nobody measured.
Marking scheme
- i. Logging; a data log.
- ii. To know when each reading was taken: changes over time, when something went wrong, which readings are missing.
- iii. Plain text, one line per reading with commas, easy for the device to add to and for programs to read.
- iv. Leave a gap in the line, because a joined line would look like readings that weren’t taken.
Practical exam
25 marksMarked by the school. Work alone at a computer, with no internet and no AI, in front of the teacher, for 1 hour 30 minutes. Write and run each program, show it working, and answer the teacher’s questions. On this page, press Edit on a program to type in it, and Run to run it.
Seed for the season. An agriculture office suggests how much seed a farmer needs for each ropani of land: rice 2.5 kg, wheat 6 kg and maize 1.5 kg. Seed is sold only in whole kg, so the amount must be rounded up (math.ceil() from the standard library’s math module rounds a number up). Ramesh wrote a module and a program, but the program stops with an error.
seeds.py
RATES = {"rice": 2.5, "wheat": 6, "maize": 1.5} # kg of seed for each ropani def seed_needed(crop, ropani): kg = RATES[crop] * ropani print(crop, "needs", kg, "kg")main.py
import seeds total = 0for crop, ropani in [("rice", 4), ("wheat", 3), ("maize", 5)]: total = total + seeds.seed_needed(crop, ropani)print("Buy", total, "kg of seed in all")It prints rice needs 10.0 kg, then stops:
Error message
Traceback (most recent call last): File "main.py", line 5, in <module> total = total + seeds.seed_needed(crop, ropani) ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'At the computer, make the two files in one folder and run main.py to see the error. Then fix them so that:
seed_needed(crop, ropani)returns the whole kg of seed, rounded up, and has a docstring;- seeds.py has tests at the end that run only when seeds.py itself is run;
- main.py prints each crop’s seed, as “rice: 10 kg”, and the total.
Run seeds.py, then main.py, in front of the teacher.
Answer
The function printed the amount and returned nothing, so it gave back None, and 0 + None is a TypeError. It must return the amount; the printing belongs in main.py.
seeds.py
"""How much seed to buy for a field."""import math RATES = {"rice": 2.5, "wheat": 6, "maize": 1.5} # kg of seed for each ropani def seed_needed(crop, ropani): """The kg of seed to buy for this crop and land, rounded up to a whole kg.""" return math.ceil(RATES[crop] * ropani) if __name__ == "__main__": # tests: an exact amount, and amounts that must be rounded up print(seed_needed("wheat", 3), "should be 18") print(seed_needed("maize", 5), "should be 8") print(seed_needed("rice", 1), "should be 3")Run by itself, seeds.py prints its tests:
Output
18 should be 188 should be 83 should be 3main.py
import seeds total = 0for crop, ropani in [("rice", 4), ("wheat", 3), ("maize", 5)]: kg = seeds.seed_needed(crop, ropani) print(crop + ":", kg, "kg") total = total + kgprint("Buy", total, "kg of seed in all")Output
rice: 10 kgwheat: 18 kgmaize: 8 kgBuy 36 kg of seed in allMaize: 1.5 × 5 = 7.5 kg, rounded up to 8.
Marking scheme
- Runs main.py and reads the error:
seed_neededreturns nothing (None), which can’t be added. seed_neededreturns the amount instead of printing it.- Rounds up with
math.ceil(withimport math), giving 8 kg of maize. - A docstring that says what the function returns.
- Tests under
if __name__ == "__main__":, including an amount that must be rounded up, which don’t run when it is imported. - main.py prints each crop’s amount and adds the returned values to the total.
- Runs both in front of the teacher: 10, 18 and 8 kg, 36 in all.
Soil tests. An agriculture cooperative in Kavre tests the soil of its members’ plots. This program makes its database and gives you ask(), which prints what a query gives. Run it, then add one ask() for each question:
- i.The tests with a pH below 5.5 (soil acid enough to need lime): the test_id, plot_id and pH, the most acid (lowest pH) first. (2)
- ii.For each plot: its plot_id, how many times it has been tested, and its lowest pH. (2)
- iii.For the tests done in Kartik: the farmer, the crop and the pH, the lowest pH first. (2)
import sqlite3 db = sqlite3.connect(":memory:")db.execute("CREATE TABLE plots (plot_id INTEGER PRIMARY KEY, farmer TEXT, ward INTEGER, crop TEXT, ropani INTEGER)")db.execute("""CREATE TABLE soil_tests (test_id INTEGER PRIMARY KEY, plot_id INTEGER REFERENCES plots(plot_id), month TEXT, ph REAL, nitrogen TEXT)""")db.executemany("INSERT INTO plots VALUES (?, ?, ?, ?, ?)", [ (1, "Ram Shrestha", 3, "potato", 8), (2, "Sita Lama", 5, "tomato", 4), (3, "Hari Dahal", 3, "maize", 10), (4, "Gita Tamang", 7, "potato", 6), (5, "Bina Thapa", 5, "cauliflower", 5),])db.executemany("INSERT INTO soil_tests VALUES (?, ?, ?, ?, ?)", [ (1, 1, "Baisakh", 5.2, "low"), (2, 2, "Baisakh", 6.4, "medium"), (3, 3, "Baisakh", 5.8, "low"), (4, 4, "Jestha", 4.9, "low"), (5, 1, "Kartik", 5.6, "medium"), (6, 5, "Kartik", 6.8, "high"), (7, 2, "Kartik", 6.1, "medium"), (8, 3, "Kartik", 5.5, "low"),]) def ask(sql): """Print each row the query gives, then a blank line.""" for row in db.execute(sql): print(row) print() ask("SELECT * FROM plots")Answer
The same program, with these three lines in place of the last one:
import sqlite3 db = sqlite3.connect(":memory:")db.execute("CREATE TABLE plots (plot_id INTEGER PRIMARY KEY, farmer TEXT, ward INTEGER, crop TEXT, ropani INTEGER)")db.execute("""CREATE TABLE soil_tests (test_id INTEGER PRIMARY KEY, plot_id INTEGER REFERENCES plots(plot_id), month TEXT, ph REAL, nitrogen TEXT)""")db.executemany("INSERT INTO plots VALUES (?, ?, ?, ?, ?)", [ (1, "Ram Shrestha", 3, "potato", 8), (2, "Sita Lama", 5, "tomato", 4), (3, "Hari Dahal", 3, "maize", 10), (4, "Gita Tamang", 7, "potato", 6), (5, "Bina Thapa", 5, "cauliflower", 5),])db.executemany("INSERT INTO soil_tests VALUES (?, ?, ?, ?, ?)", [ (1, 1, "Baisakh", 5.2, "low"), (2, 2, "Baisakh", 6.4, "medium"), (3, 3, "Baisakh", 5.8, "low"), (4, 4, "Jestha", 4.9, "low"), (5, 1, "Kartik", 5.6, "medium"), (6, 5, "Kartik", 6.8, "high"), (7, 2, "Kartik", 6.1, "medium"), (8, 3, "Kartik", 5.5, "low"),]) def ask(sql): """Print each row the query gives, then a blank line.""" for row in db.execute(sql): print(row) print() ask("SELECT test_id, plot_id, ph FROM soil_tests WHERE ph < 5.5 ORDER BY ph")ask("SELECT plot_id, COUNT(*), MIN(ph) FROM soil_tests GROUP BY plot_id")ask("""SELECT plots.farmer, plots.crop, soil_tests.ph FROM soil_tests JOIN plots ON soil_tests.plot_id = plots.plot_id WHERE soil_tests.month = 'Kartik' ORDER BY soil_tests.ph""")Output
(4, 4, 4.9)(1, 1, 5.2) (1, 2, 5.2)(2, 2, 6.1)(3, 2, 5.5)(4, 1, 4.9)(5, 1, 6.8) ('Hari Dahal', 'maize', 5.5)('Ram Shrestha', 'potato', 5.6)('Sita Lama', 'tomato', 6.1)('Bina Thapa', 'cauliflower', 6.8)Test 8, with a pH of exactly 5.5, is not below 5.5, so it isn’t in the first answer. (The tests are made up for this paper.)
Marking scheme
- i.
WHERE ph < 5.5, selecting test_id, plot_id and ph. - i.
ORDER BY ph(lowest first), giving tests 4 and 1. - ii.
GROUP BY plot_idwithCOUNT(*). - ii.
MIN(ph)for each plot, giving the five rows above. - iii. A JOIN of soil_tests and plots
ON soil_tests.plot_id = plots.plot_id. - iii. Only Kartik’s tests, ordered by pH: Hari Dahal 5.5, Ram Shrestha 5.6, Sita Lama 6.1, Bina Thapa 6.8.
The vet’s rounds. The livestock vet in Liwang, Rolpa, walks to villages to treat animals. The dictionary below shows which villages have a trail between them (a simplified, made-up map). Write a function fewest_trails(graph, start, goal) that returns the number of trails on a route with the fewest trails, or None if there is no way. Then:
- print the fewest trails from Liwang to Rangsi, to Ghartigaun and to Thawang;
- the vet can walk at most 2 trails in a day and come back: using your function, print every village that is more than 2 trails from Liwang, where he must stay the night.
rolpa = { "Liwang": ["Sulichaur", "Mirul", "Jaimakasala"], "Sulichaur": ["Liwang", "Holeri"], "Mirul": ["Liwang", "Thawang", "Korchabang"], "Jaimakasala": ["Liwang", "Holeri"], "Holeri": ["Sulichaur", "Jaimakasala", "Ghartigaun"], "Thawang": ["Mirul", "Jelbang"], "Korchabang": ["Mirul", "Jelbang"], "Jelbang": ["Thawang", "Korchabang", "Rangsi"], "Rangsi": ["Jelbang"], "Ghartigaun": ["Holeri"],} # Write fewest_trails hereAnswer
rolpa = { "Liwang": ["Sulichaur", "Mirul", "Jaimakasala"], "Sulichaur": ["Liwang", "Holeri"], "Mirul": ["Liwang", "Thawang", "Korchabang"], "Jaimakasala": ["Liwang", "Holeri"], "Holeri": ["Sulichaur", "Jaimakasala", "Ghartigaun"], "Thawang": ["Mirul", "Jelbang"], "Korchabang": ["Mirul", "Jelbang"], "Jelbang": ["Thawang", "Korchabang", "Rangsi"], "Rangsi": ["Jelbang"], "Ghartigaun": ["Holeri"],} def fewest_trails(graph, start, goal): """The fewest trails from start to goal, or None if there is no way.""" steps = {start: 0} to_visit = [start] while len(to_visit) > 0: village = to_visit.pop(0) if village == goal: return steps[village] for nxt in graph[village]: if nxt not in steps: steps[nxt] = steps[village] + 1 to_visit.append(nxt) return None for goal in ["Rangsi", "Ghartigaun", "Thawang"]: print("Liwang to", goal + ":", fewest_trails(rolpa, "Liwang", goal), "trails") print("Stay the night at:")for village in rolpa: if fewest_trails(rolpa, "Liwang", village) > 2: print(village)Output
Liwang to Rangsi: 4 trailsLiwang to Ghartigaun: 3 trailsLiwang to Thawang: 2 trailsStay the night at:JelbangRangsiGhartigaunEvery village can be reached, so the function never returns None here; on a map where one couldn’t, None > 2 would be an error, and the loop would need to check for None first.
Marking scheme
- A function with the graph, start and goal, that starts its queue with the start at 0 steps.
- A queue: takes from the front with
pop(0)and adds to the back withappend(). - Records a village’s steps (one more than the village it was reached from) when it is first added, and never adds it twice.
- Returns the steps when the goal is taken from the queue, and
Noneif the queue runs out. - Prints 4, 3 and 2 trails.
- Loops over every village, calls the function for each and prints those more than 2 trails away: Jelbang, Rangsi, Ghartigaun.
Viva. The teacher asks each student about their own work, for example:
- i.Why did you round up with
math.ceil, not withround()? What wouldround()give for 1 ropani of rice? (2) - ii.Why does the soil_tests table have a test_id of its own, instead of using plot_id as its primary key? (2)
- iii.Your function returns a number, not a route. How does it know each village’s number of trails, and why is the first number it finds for the goal the fewest? (2)
Answer
- i.Seed is sold in whole kg, and too little seed leaves part of the field unsown, so the amount must never be rounded down.
round()goes to the nearest whole number, sometimes down: 1 ropani of rice needs 2.5 kg, andround(2.5)gives 2 (Python rounds a half to the even number), half a kg short.math.ceil(2.5)gives 3. - ii.A plot is tested many times (plot 1 in Baisakh and in Kartik), so plot_id is repeated in soil_tests and can’t be a primary key, which must be different in every row. It is a foreign key pointing to the plot; test_id names each test. One plot has many tests: a one-to-many relationship.
- iii.When a village is first added, its steps are its neighbor’s steps plus one, kept in the
stepsdictionary. The queue takes places in the order they were added, so all villages 1 trail away are visited before any 2 away, and so on in rings; the first time the goal comes off the queue, no shorter route can be left.
Marking scheme
- i. Seed must never be rounded down (too little to sow the field).
- i.
round(2.5)gives 2;math.ceilgives 3. - ii. A plot has many tests, so plot_id repeats and can’t be the primary key.
- ii. plot_id is a foreign key to plots; test_id is different in every row (one-to-many).
- iii. Each new village gets its neighbor’s steps plus one, kept in a dictionary.
- iii. The queue visits places in rings (all 1 away before 2 away), so the first time the goal is reached is the fewest.
Your score
0 / 50 theory
0 / 25 practical
29 questions not marked yet
| Section A | – | Full marks 10 |
| Section B | – | Full marks 20 |
| Section C | – | Full marks 20 |
| Practical exam | – | Full marks 25 |
Marks lost, by unit
Mark a question to see your score here.
