Lab: Print Amira's first shelf card
Module 1 · Lab · About 45 minutes · Needs: lessons 1 to 3 of this module
What you are building
Amira's question for this module was "Can the computer print a card for one book?" In this lab you answer it properly. The card is for Frankenstein, loan L04, the copy Jonah borrowed on Monday 14 September 2026 and still has today, Wednesday 14 October.
In Lesson 1 every fact on the card was typed straight into the text. Here every fact lives in a variable first, and the card is printed from those names. The numbers are worked out by Python, not by you: the due day and the days late come from the shelf rules. At the end you save the whole thing as a script, card.py, so the same card comes out every time anyone runs it. Use one new Colab notebook for the whole lab and run the cells in order.
Step 1: Start a fresh notebook and check Python
A fresh notebook remembers nothing, which is exactly what you want: every name the card uses will be made in this lab. Open a new notebook in Colab, name it module-01-lab.ipynb, and check which Python you have before you write anything else.
!python --versionCode walkthrough
!sends the line to the computer's command line, outside the notebook.python --versionasks thepythonprogram for its version and does nothing else. This is the same Python that runscard.pyin Step 6.
You should see:
Python 3.12.15The last number may differ. 3.12 is what matters: every output in this lab was captured with it. If yours starts 3.13 or higher, the lab still works.
Step 2: Name the shelf's rules
The card depends on the shelf's rules, so they come first. Each rule gets a constant: a name in capital letters that the program promises never to change. These four names are fixed for the whole course. A fifth, TODAY_DAY, holds today as a shelf day. A shelf day counts days from the opening, 1 September, so 14 October is day 44.
LOAN_DAYS = 14 # a loan lasts 14 days
FEE_PER_DAY = 20 # late fee, in pence, for each day after the due date
FEE_CAP = 300 # the most one loan can be charged, in pence
MAX_BOOKS = 3 # the most books one member may have out at once
TODAY_DAY = 44 # Wednesday 14 October 2026, as a shelf day
print(LOAN_DAYS, FEE_PER_DAY, FEE_CAP, MAX_BOOKS, TODAY_DAY)Code walkthrough
- Each line is an assignment:
=makes the name on the left point at the number on the right. - Everything after
#is a comment, which Python skips. Each comment says what the number measures and its unit, so nobody reads 20 as pounds. printshows the five values on one line, with a space between each.
You should see:
14 20 300 3 44Step 3: Hold the book
Next, the book itself. Its title, author and year belong together, so name them in one line with unpacking: three names on the left of =, three values on the right, paired by position. Then ask Python for each value's type, because the card will treat text and numbers differently.
title, author, year = "Frankenstein", "Mary Shelley", 1818
print(title, "by", author, year)
print(type(title))
print(type(year))Code walkthrough
- Line 1 makes three names at once. The first name gets the first value, and so on.
"Frankenstein"and"Mary Shelley"are in quotation marks, so they are text, astr.1818has none, so it is a whole number, anint.type(...)reports the type of the value inside the brackets.
You should see:
Frankenstein by Mary Shelley 1818
<class 'str'>
<class 'int'>Read <class 'int'> as "this is an int".
Step 4: Hold the loan and work out its days
Now the loan. Four facts come straight from the record: the loan id, the member, the borrow date in words, and the borrow date as a shelf day. Two more are worked out from them. The due day is the borrow day plus the loan period. The days late are today minus the due day.
loan_id = "L04"
member = "Jonah"
borrowed = "Monday 14 September 2026"
borrowed_day = 14 # shelf day: 14 September is day 14
due_day = borrowed_day + LOAN_DAYS
days_late = TODAY_DAY - due_day
print(loan_id, member, borrowed)
print("due on day", due_day, "and", days_late, "days late")Code walkthrough
borrowedis text for people to read.borrowed_dayis a number Python can count with. They describe the same day, and the card uses both.borrowed_day + LOAN_DAYSis an expression: Python works it out to one value,28, anddue_daypoints at that value.TODAY_DAY - due_dayworks out to16. The namedays_latesays what the number means.
You should see:
L04 Jonah Monday 14 September 2026
due on day 28 and 16 days lateThese two numbers agree with Lesson 1: Jonah's book was due back on Monday 28 September, and today it is 16 days late. Write a number down by hand before Python works it out, and you will always know whether to trust the answer. The incident file for this module shows why that habit matters.
Step 5: Print the card in the notebook
Every fact now has a name, so the card is only print lines. Each line mixes text you type, in quotation marks, with names, which print replaces with their values. A comma separates the parts, and print puts one space between them.
print("BOOKNOOK SHELF CARD")
print(title)
print("by", author)
print("first published", year)
print("Loan", loan_id, "held by", member)
print("Borrowed", borrowed)
print("Due on shelf day", due_day)
print("Days late on shelf day", TODAY_DAY, "is", days_late)
print("Late fee:", FEE_PER_DAY, "pence a day, at most", FEE_CAP, "pence")
print("Limit:", MAX_BOOKS, "books per member")Code walkthrough
print(title)has no quotation marks, so Python prints the valuetitlepoints at,Frankenstein, not the word "title".- The last two lines print the rules from their constants, so the card can never disagree with the rules.
You should see:
BOOKNOOK SHELF CARD
Frankenstein
by Mary Shelley
first published 1818
Loan L04 held by Jonah
Borrowed Monday 14 September 2026
Due on shelf day 28
Days late on shelf day 44 is 16
Late fee: 20 pence a day, at most 300 pence
Limit: 3 books per memberThe fee itself is missing on purpose. Sixteen days at 20 pence would be 320, but the cap stops it at 300; choosing the smaller of two numbers is Module 2's job.
Step 6: Save the card as a script and run it
The card in Step 5 works only because Steps 2 to 4 ran first in this session. Close the tab and those names are gone. A script, a .py file, keeps everything together. %%writefile saves the cell as a file instead of running it, so the cell must hold every name the card uses, then the print lines.
%%writefile card.py
# Amira's first shelf card: loan L04, asked for on Wednesday 14 October 2026
LOAN_DAYS = 14 # a loan lasts 14 days
FEE_PER_DAY = 20 # late fee, in pence, for each day after the due date
FEE_CAP = 300 # the most one loan can be charged, in pence
MAX_BOOKS = 3 # the most books one member may have out at once
TODAY_DAY = 44 # Wednesday 14 October 2026, as a shelf day
title, author, year = "Frankenstein", "Mary Shelley", 1818
loan_id = "L04"
member = "Jonah"
borrowed = "Monday 14 September 2026"
borrowed_day = 14 # shelf day: 14 September is day 14
due_day = borrowed_day + LOAN_DAYS
days_late = TODAY_DAY - due_day
print("BOOKNOOK SHELF CARD")
print(title)
print("by", author)
print("first published", year)
print("Loan", loan_id, "held by", member)
print("Borrowed", borrowed)
print("Due on shelf day", due_day)
print("Days late on shelf day", TODAY_DAY, "is", days_late)
print("Late fee:", FEE_PER_DAY, "pence a day, at most", FEE_CAP, "pence")
print("Limit:", MAX_BOOKS, "books per member")Code walkthrough
%%writefile card.pymust be the very first line. Nothing below it runs now; it is saved intocard.py.- The script is Steps 2 to 5 in one place: rules first, then the book and loan, then the card. A name must be made before the line that uses it.
- The blank lines are only for the reader. Python skips them.
You should see:
Writing card.pyNow run it. !python card.py starts a brand new Python, which reads the file from its first line to its last, once.
!python card.pyCode walkthrough
python card.pyruns the file. This new Python knows nothing about the notebook's names; everything it uses is insidecard.py.
You should see:
BOOKNOOK SHELF CARD
Frankenstein
by Mary Shelley
first published 1818
Loan L04 held by Jonah
Borrowed Monday 14 September 2026
Due on shelf day 28
Days late on shelf day 44 is 16
Late fee: 20 pence a day, at most 300 pence
Limit: 3 books per memberThe same ten lines as Step 5. Run the cell again tomorrow and you get them again.
Check your work
Paste this cell as it is. It runs card.py the way !python does, keeps what it prints, and asks four yes-or-no questions about it. Later modules explain every part; for now, read the answers.
import subprocess, sys
result = subprocess.run([sys.executable, "card.py"], capture_output=True, text=True)
lines = result.stdout.splitlines()
print(len(lines) == 10)
print(lines[0] == "BOOKNOOK SHELF CARD")
print(lines[7] == "Days late on shelf day 44 is 16")
print(result.stderr == "")Code walkthrough
subprocess.run(...)runscard.pywith the notebook's own Python and keeps its output inresult.linesis that output cut into separate lines.lines[0]is the first line andlines[7]the eighth: Python counts from 0.==asks "are these two the same?" and givesTrueorFalse.result.stderrholds any error message. Empty meanscard.pyran without one.
You should see:
True
True
True
TrueA False points at one question. Compare your card.py with Step 6 one character at a time, run the %%writefile cell again, then this cell.
Break it
Try saving only the print lines, as if the script could borrow the notebook's names. It fails on purpose, so it is shown as text: type the first cell, then run the script in a second cell with !python short_card.py.
%%writefile short_card.py
print("BOOKNOOK SHELF CARD")
print(title)Run this and you will see:
BOOKNOOK SHELF CARD
Traceback (most recent call last):
File "/content/short_card.py", line 2, in <module>
print(title)
^^^^^
NameError: name 'title' is not defined. Did you mean: 'tuple'?The output was captured with Python 3.12. Read it from the last line up. A NameError means Python met a name it does not know. But title exists in your notebook: you made it in Step 3. The script ran in a brand new Python, which never saw that cell. The heading did print first, because a NameError is found only when Python reaches the line. The "Did you mean" guess, tuple, is just the nearest name Python knows, and no help here.
That is the difference between the two places your code can live. A notebook remembers names between cells, in the order you ran them. A script remembers nothing it does not contain. This is why card.py holds every rule and every fact, and why it gives the same card on any computer, any day.
What you added to the Booknook shelf
- The four shelf rules as constants,
LOAN_DAYS,FEE_PER_DAY,FEE_CAPandMAX_BOOKS, plusTODAY_DAY = 44. - Frankenstein and loan L04 held in variables, with the due day (28) and days late (16) worked out by Python.
card.py, a script that prints Amira's first shelf card the same way every time, and a check that proves it.
Going further
- Make a second card for Lena's loan L23: Jane Eyre, Charlotte Brontë, 1847, borrowed Tuesday 29 September 2026, shelf day 29. You should get due day 43 and 1 day late.
- Change
LOAN_DAYSto 21 in a copy ofcard.pyand predict the days late before you run it. - Add a comment to
card.pyabovedue_daythat says why the due day is what it is.