Exam practice
Every question from the end of every unit, with hints and answers to open. After you check an answer, mark how you did, and come back to the ones you didn’t get.
12 questions
Unit 1 · Bigger Programs
Explain these words, with an example of each from this unit: module, library, namespace, side effect, API.
Answer
- Module: a file of Python code whose functions and variables other programs can import. Example: grading.py, imported with
import grading. - Library: a collection of modules written for other programs to use. Example: Python’s standard library (statistics, csv, json), or nepali-datetime from PyPI.
- Namespace: a box of names, so that the same name in two places doesn’t clash. Example: grading.py’s PASS_MARK is
grading.PASS_MARK, separate from any PASS_MARK in the main program; each function call has its own namespace for its local variables. - Side effect: anything a function does besides returning a value. Example: print_report() prints;
top_three()sorted the list it was given. - API: the published way for one program to ask another for something. Example: the functions of the statistics module and their documentation; the Open-Meteo web API, asked with an address and answering in JSON.
What does this program print? Explain each line of output using the idea of scope.
x = 10 def f(x): x = x * 2 return x def g(): return x + 1 print(f(3))print(g())print(x)Answer
Output
61110f(3): the parameter x is f’s own local variable, 3; it becomes 6 and is returned. The global x is not touched.g(): g has no x of its own (it never assigns one), so Python looks in the global box and finds 10; it returns 11.print(x): in the program, x is the global x, which nothing changed: 10.
Read this function as the unit showed (in, builds, out, side effects), and say in one sentence what it does. Then give it a better name and a docstring.
def h(students, subject): best = students[0] for s in students: if s[subject] > best[subject]: best = s return best["name"], best[subject]Answer
- In: students, a list of dictionaries (each used as
s[subject]andbest["name"]), and subject, a string used as a key. - Builds: one variable, best, the student with the highest mark so far, starting from the first.
- Out: a tuple of two values: the best student’s name and their mark in that subject.
- Side effects: none: it prints nothing and doesn’t change the list. (It fails with IndexError if the list is empty.)
In one sentence: it finds the student with the highest mark in one subject, and returns their name and mark.
def top_student(students, subject): """The name and mark of the student with the highest mark in subject. students must not be empty; if two tie, the first is returned."""A student writes this function to give everyone 5 grace marks for a hard question, and checks it with science = [63, 21, 72], new = add_grace(science). Later the program prints science and shows the grace marks already added. Explain why, and rewrite the function so that the original list is not changed.
def add_grace(marks): for i in range(len(marks)): marks[i] = marks[i] + 5 return marksAnswer
The parameter marks is not a copy: it is a second name for the same list as science. marks[i] = … changes that list in place, so science has the grace marks too, and new is the very same list.
A version that builds a new list and leaves the old one alone:
def add_grace(marks): """A new list: each mark plus 5. marks itself is not changed.""" return [m + 5 for m in marks](or with a loop: new = [], then new.append(m + 5) for each m, then return new).
Rewrite this program without the global line, so that add_sale is a pure function. Why is your version better?
total = 0 def add_sale(price, plates): global total total = total + price * plates add_sale(150, 2)add_sale(120, 3)print("Today's sales: Rs", total)Answer
def add_sale(total, price, plates): """The new total after selling plates at price each.""" return total + price * plates total = 0total = add_sale(total, 150, 2)total = add_sale(total, 120, 3)print("Today's sales: Rs", total)It prints Today's sales: Rs 660, as before. It is better because the function depends only on what it is given and changes nothing outside itself: it can be tested on its own (add_sale(0, 150, 2) must be 300), reused in another program, and when total is wrong, the only lines that change it are in plain sight in the program.
What is the difference between import statistics and from statistics import mean? Write the line that prints the mean of marks after each.
Answer
import statistics runs the module and makes one name, statistics, in your program; everything in it is reached through it: print(statistics.mean(marks)).from statistics import mean also runs the module, but makes only the name mean in your program, so it is used without the module’s name: print(mean(marks)). The name statistics is not made.
The first makes clear where each name comes from; the second is shorter for a name used often.
A file shop.py ends with these lines. What do they do when shop.py is run by itself? And when a program runs import shop?
if __name__ == "__main__": print(bill_total(150, 2))Answer
Run by itself, __name__ is "__main__", so the condition is true and the line prints the bill total for 2 plates at Rs 150 (a test of bill_total: it should print 300).
Imported, __name__ is "shop", so the condition is false and nothing is printed: the program that imports shop gets the function without the test running.
You need a library to make QR codes for your school’s fee receipts. Searching PyPI, you find several. List four things you would check before choosing and installing one, and why each matters.
Answer
- That it is the real one: the exact name, copied from its official documentation or PyPI page, because harmful packages use names one letter away from popular ones, and installing a package runs its code.
- That it is looked after: a recent version, documentation, problems answered, so it works with your Python and its mistakes get fixed.
- That it is widely used: many users mean many people have tested it and found its bugs.
- Its license: that it allows your use (for the school, perhaps sold or shared), and what credit it asks for.
(Also good: whether you need it at all, and how many other libraries it brings with it.)
The documentation of a function says:
split_bill(total, people, *, tip=0): “Returns how much each person pays, rounded up to the next rupee. Raises ValueError if people is less than 1.”
- a.Which arguments must you give? Which can you leave out?
- b.Write a call for a Rs 1,000 bill shared by 3 friends with a Rs 50 tip.
- c.Write a few lines that call it for 0 people without the program stopping, and print “Nobody to pay!” instead.
Answer
- a.total and people must be given; tip has a default (0) and can be left out. Because it comes after
*, it can only be given by name. - b.
split_bill(1000, 3, tip=50)(each pays 1,050 ÷ 3 = Rs 350).
c.
try: print(split_bill(1000, 0))except ValueError: print("Nobody to pay!")A program asks a web API for a district’s information. Explain what each part of this address is for: https://api.example.com/nepal/v1/districts?province=Karnali. Then say what a program should do if the API answers 404, and if there is no internet at all.
Answer
https://: the way of connecting (HTTPS, encrypted).api.example.com: the computer to ask, the API’s server./nepal/v1/districts: the endpoint, which data is wanted (here, districts, from version 1 of the API).?province=Karnali: a query parameter, the detail of the question: only Karnali’s districts.
If the API answers 404, nothing is at that address: the program should tell the user plainly (for example, “No such district: check the spelling”) instead of trying to use data that isn’t there. With no internet, fetching raises an error (OSError): the program should catch it with try/except and say “Couldn’t reach the API. Are you online?”, perhaps offering to try again later, rather than stopping with a traceback.
Turn this JSON answer into Python, and write the lines that print Rara and 10.8.
{"province": "Karnali", "lakes": [{"name": "Rara", "area_km2": 10.8}, {"name": "Phoksundo", "area_km2": 4.9}]}Answer
import json data = json.loads(text) # text holds the JSON aboveprint(data["lakes"][0]["name"])print(data["lakes"][0]["area_km2"])data is a dictionary; data["lakes"] a list of two dictionaries; [0] the first, Rara’s; ["name"] and ["area_km2"] its values. (In Python, the JSON’s objects are dictionaries, its arrays lists, its numbers ints or floats.)
A school’s program has 3,000 lines in one file, written by one teacher who has now left. Explain to the school’s new computer teacher how they could split it into modules, step by step, and why it is worth doing.
Answer
Steps:
- Read the program and list what it does, in areas: for example reading and saving students’ data, the school’s rules (fees, grades, attendance), and printing reports.
- Move the functions of each area into a module of its own (students_file.py, rules.py, reports.py), one job each, with a docstring at the top saying what the module is for.
- Write down each module’s interface: the functions others use, with docstrings. Keep the rest private to the module (by convention, names starting with _).
- Replace global variables that change with parameters and return values; keep only constants as globals.
- Add tests to each module under
if __name__ == "__main__":, and run the whole program after each move to check it still gives the same results, changing one thing at a time.
Why: each area can be found, understood and changed in one place; a change to the rules can’t break the printing; modules can be tested on their own; two teachers can work on different modules at once; and the modules can be reused in other programs, such as a new attendance app.
