Lesson 2: Trying lines out and saving them as scripts
Module 1 · Lesson 2 · About 40 minutes · Needs: Lesson 1 (running a cell, print, reading the last line of an error)The situation
Amira wants a card for one book on the shelf. Before you write the card, you need the numbers on it. Jonah borrowed Frankenstein (loan L04) on 14 September. Until Module 7 brings real dates, the course counts shelf days: days since the shelf opened, so 14 September is day 14 and today, Wednesday 14 October, is day 44. A loan lasts 14 days. When is Jonah's book due, and how late is it?
You will work it out one line at a time, then save the lines in a file, so the same answer comes out every time.
A real case, first
The place where you type Python one line at a time is called the interactive prompt. In 2024 Python's core developers replaced it. PEP 762, "REPL-acing the default REPL" (2024), describes the new prompt that arrived in Python 3.13: it shows colour, and it makes editing several lines at once much easier. A PEP (Python Enhancement Proposal) is the public document that proposes and explains a change to Python.
That matters to you because Colab runs Python 3.12, so you see the older, plainer prompt. In 3.12, typing exit on its own does not leave the prompt; it prints a hint telling you to type exit() instead. In 3.13 and later, exit alone works. This lesson's transcripts were captured on 3.12. The general point: your Python version decides small details of what you see, so knowing it is part of reading any output.
What you will be able to do
- Tell an expression from a statement, and predict what each shows at the prompt
- Use the interactive prompt to test a line before you keep it
- Write a script file with
%%writefileand run it with!python - Indent a block correctly and read the three common indentation errors
- Check which Python you are running, in Colab and on your own computer
1. Expressions and statements (Essential)
Every line of Python you will ever write is built from two kinds of piece. Knowing which is which tells you, before you run anything, whether a line will show you a result.
At the interactive prompt you type one line, and Python answers at once. In a script you write many lines into a file, and Python runs the whole file. The difference between them starts with expressions.
An expression is a piece of code that Python works out to a single value. 14 + 14 is an expression: Python adds the numbers and the value is 28. That is Jonah's due day: borrowed on day 14, plus 14 days of loan. The + adds, - takes away, and * multiplies; Module 2 covers the rest.
A statement is one complete instruction: a line that Python carries out. print(44 - 28) is a statement. Inside its brackets sits the expression 44 - 28, which works out to 16, the number of days Jonah is late. import sys is a statement too, and it holds no expression at all. Statements do things; expressions produce the values they use.
Here is the same idea in a Colab cell. A cell shows the value of its last line underneath.
14 + 14
44 - 28Code walkthrough
- Line 1 is an expression. Python works out
28, but it is not the last line, so nothing is shown. - Line 2 is the last line, so Colab shows its value.
Output
16Only one number appeared. To see more, use print, which shows its value on any line.
print(14 + 14)
print(44 - 28)Code walkthrough
- Each line is a statement. The expression inside the brackets is worked out first, then
printshows the result.
Output
28
162. The interactive prompt, the REPL (Essential)
The prompt is where you try things. When you are not sure what a line does, typing it at the prompt and seeing the answer is quicker than reasoning about it.
The prompt has a name: the REPL, short for read, evaluate, print, loop. Python reads the line you type, evaluates it (works it out), prints the result, and loops back to wait for the next line. A Colab cell behaves like a REPL that takes several lines at once.
The REPL marks its lines with symbols. >>> is the prompt: Python is waiting for a new line. ... means Python is waiting for more of the same instruction, because the line above ended with a colon. You type what comes after the symbols, never the symbols themselves. Here is a real session, captured on Python 3.12:
>>> 14 + 14
28
>>> 44 - 28
16
>>> print(44 - 28)
16
>>> import sys
>>>Each expression was echoed straight back. print showed its value. import sys is a statement with no value, so Python showed nothing and gave a new prompt.
There is one small difference between echoing and printing. Type text in quotation marks and the REPL echoes it the way Python writes it, quotes included. print shows it the way a person reads it:
>>> "Frankenstein"
'Frankenstein'
>>> print("Frankenstein")
FrankensteinThe echo is for you, checking a value. print is for the people who read the output, like Amira.
3. Writing a script file with %%writefile (Essential)
Lines typed at the prompt vanish when you close it. A file keeps them, so Amira gets the same card tomorrow without anyone retyping it.
A script is a plain text file of Python code whose name ends in .py. In Colab you make one with %%writefile. It is a cell magic: a command for the notebook, not Python, which is why it starts with two percent signs. It must be the very first line of the cell, and it saves the rest of the cell into the named file instead of running it.
%%writefile card.py
print("Frankenstein by Mary Shelley")
print("Loan L04, Jonah, borrowed on day", 14)
print("Due on day", 14 + 14)
print("Days late on day 44:", 44 - 28)Code walkthrough
%%writefile card.pynames the file. Nothing below it runs yet; it is only saved.- Each
printline is a statement. A comma insideprintseparates two values, andprintputs a space between them. 14 + 14and44 - 28are expressions inside the statements, worked out when the script runs.
Output
Writing card.pyThe file now sits in Colab's working folder. Click the folder icon in the left sidebar to see card.py. Running the cell again prints Overwriting card.py and replaces the file.
4. Running a script with python (Essential)
A saved file does nothing until you run it. Running it is how the card gets printed, and later how Amira's whole morning report will run from one command.
!python card.py runs the file. The ! at the start sends the line to the computer's command line, outside the notebook. There, python is the program that runs Python files, and card.py is the file to give it.
!python card.pyCode walkthrough
!means "this is a command for the computer, not Python code".python card.pystarts a fresh Python, which reads the file and runs it.
Output
Frankenstein by Mary Shelley
Loan L04, Jonah, borrowed on day 14
Due on day 28
Days late on day 44: 16A script runs from its first line to its last, in order, once, then that Python stops. So the same file gives the same four lines every time.
Break it: an expression with no print
At the prompt, 44 - 28 showed 16. In a script, nobody is there to see an echo, so a bare expression is worked out and thrown away.
%%writefile silent.py
14 + 14
44 - 28Code walkthrough
- Two bare expressions, with no
print, saved assilent.py.
Output
Writing silent.py!python silent.pyCode walkthrough
- Python runs both lines without complaint and works out both values. It shows nothing at all: the output area stays empty.
The fix is to wrap each value in print. A script shows only what you print.
5. Indentation and whitespace rules (Essential)
Python is unusual: the spaces at the start of a line are part of its grammar. Get them wrong and the script does not run at all, so this is worth five careful minutes now.
Some lines end in a colon, :. A colon means "a group of lines follows". That group is called a block, and you mark which lines belong to it by indenting them: moving them right with spaces. The if line below asks whether 44 is greater than 28 (> means "greater than"); Module 4 teaches if properly. For now, watch the shape.
print("Shelf check for loan L04")
if 44 > 28:
print("Overdue")
print("Days late:", 44 - 28)
print("Check finished")Code walkthrough
- Line 1 is not indented, so it always runs.
- Line 2 ends in a colon. It opens a block.
- Lines 3 and 4 start with four spaces, so they are the block. They run only if the
ifis true, and it is. - Line 5 is back at the left edge, so the block has ended.
Output
Shelf check for loan L04
Overdue
Days late: 16
Check finishedWhitespace means spaces, tabs and line breaks. Inside a line, Python ignores extra spaces: 44-28 and 44 - 28 are the same. At the start of a line, spaces are counted.
Use four spaces for each level of indent. That is the rule in PEP 8, Python's style guide, and Colab inserts four spaces for you when you press Enter after a colon. A tab is a different, invisible character. Mixing tabs and spaces in one block makes Python stop with a TabError, so use spaces only.
Three mistakes cause almost every indentation error, and the error's last line names which one you made. Two of them, at the prompt:
>>> print(16)
File "<stdin>", line 1
print(16)
IndentationError: unexpected indent
>>> if 44 > 28:
... print("overdue")
File "<stdin>", line 2
print("overdue")
^^^^^
IndentationError: expected an indented block after 'if' statement on line 1The first line was indented with nothing above to belong to. The second forgot to indent the block under the colon.
Break it: one missing indent sinks the whole script
Save the check as a script, but leave out the indent under the colon.
%%writefile broken.py
print("Shelf check for loan L04")
if 44 > 28:
print("Overdue")Code walkthrough
- Line 3 should be indented under the
ifon line 2, and it is not.
Output
Writing broken.py!python broken.py || echo "Python reported a failure"Code walkthrough
!python broken.pyruns the script, as before.||is a command-line word for "if the command on the left fails, run the one on the right".echoprints its text. So the last line appears only because Python reported a failure.
Output
File "/content/broken.py", line 3
print("Overdue")
^^^^^
IndentationError: expected an indented block after 'if' statement on line 2
Python reported a failureLook at what is missing: the first line, Shelf check for loan L04, never printed, although it was correct. Python reads the whole file and checks its grammar before it runs any line. One bad indent stops everything. The fix is four spaces before print("Overdue").
6. Which Python am I running (Recommended)
Different Python versions differ in small ways, as the real case showed. When your output does not match a lesson's, the version is the first thing to check.
A Python version has three numbers. In 3.12.15, 3 is the major version, 12 the minor version and 15 the patch. New features arrive with a new minor version; a patch only fixes bugs. So 3.12 is what matters, and the course is written for it.
import sys
print(sys.version_info)Code walkthrough
import sysbrings insys, the part of Python that knows about Python itself. Module 7 explainsimport.sys.version_infoholds the version of the Python running this notebook, as named parts.
Output
sys.version_info(major=3, minor=12, micro=15, releaselevel='final', serial=0)Python calls the patch number micro. Yours may show a different patch number; major=3, minor=12 is what to check. You can also ask the command line:
!python --versionCode walkthrough
--versionasks thepythonprogram for its version and nothing else. This is the Python that!python card.pyused.
Output
Python 3.12.15If either shows 3.13 or higher, the course still works, because it uses nothing later versions removed. You would notice the newer prompt from PEP 762.
7. Running Python on your own computer (Recommended)
Colab is a borrowed computer. Sooner or later you will want Python on your own, where files stay put. Nothing here is needed for the course.
On your own computer you use a terminal: a window where you type commands, the same kind of command ! sends in Colab. Install Python 3.12 by following 07-run-locally.md. Then, in a terminal (on Windows, type py -V:3.12 wherever this shows python3.12):
python3.12 --version
python3.12
python3.12 card.pyThese were not run in Colab; they come from the course's run-locally page. The first prints the version. The second starts the REPL; type exit() to leave. The third runs a script in the terminal's current folder. Only the ! is gone.
In production
Working programmers use both modes daily. The REPL is a scratch pad: try one expression, check a value, copy the line that works into a file. Scripts are what runs for real, because a file can be shared, reviewed and run again the same way. Python's own tutorial opens the same way, with starting the interpreter and using it interactively (Python tutorial, "Using the Python Interpreter"). Indentation is part of the language definition, so code editors insert four spaces automatically. When two people get different output from one script, comparing versions comes first.
What you added to the Booknook shelf
- Jonah's due day (28) and days late (16) for loan L04, worked out at the prompt
card.py, a four-line script that prints Frankenstein's card the same way every run- A habit of checking the version and reading an indentation error's last line
Check yourself
- In a Colab cell holding
14 + 14on line 1 and44 - 28on line 2, what appears, and why?
Only 16. A cell shows the value of its last line only; the first expression is worked out and not shown.
- You save
44 - 28alone indays.pyand run!python days.py. What do you see?
Nothing. A script never echoes values; it shows only what you print.
- What does
...at the start of a REPL line mean?
Python is waiting for more of the same instruction, usually the block under a line that ended in a colon.
- A script's first line is correct, but line 3 has a missing indent. Does line 1 print?
No. Python checks the grammar of the whole file before running any of it, so the IndentationError stops every line.
Exercise
Kwame's loan L21 of Pride and Prejudice started on shelf day 26. Write a script due.py with %%writefile that prints exactly these two lines, working the numbers out with expressions inside print (due day is borrow day plus 14; days late is 44 minus the due day):
Due on day 40
Days late on day 44: 4Then run this check cell. Paste it as it is: it runs your script and compares what it prints with the two lines above. Module 10 explains how.
import subprocess, sys
result = subprocess.run([sys.executable, "due.py"], capture_output=True, text=True)
print(result.stdout == "Due on day 40\nDays late on day 44: 4\n")Code walkthrough
subprocess.runrunsdue.pywith the same Python as the notebook and keeps what it prints inresult.stdout.==asks "are these two the same?".\ninside the quotes stands for the end of a line. The check printsTruewhen your output matches exactly, andFalsewhen it does not (or whendue.pydoes not exist yet).
%%writefile due.py
print("Due on day", 26 + 14)
print("Days late on day 44:", 44 - 40)Code walkthrough
- Two statements, each with an expression inside. Run
!python due.py, then the check cell again: it printsTrue.
Key terms
| Term | Meaning |
|---|---|
| Expression | A piece of code that works out to one value, such as 14 + 14 |
| Statement | One complete instruction that Python carries out, such as print(44 - 28) |
| REPL | Read, evaluate, print, loop: Python's interactive prompt |
| Prompt | >>>, the sign that the REPL is waiting for a line; ... means "more of the same instruction" |
| Script | A text file of Python code ending in .py, run from top to bottom |
| Cell magic | A notebook command starting with %%, such as %%writefile |
| Block | The indented lines under a line that ends in a colon |
| Indentation | Spaces at the start of a line; four per level, never tabs |
| Whitespace | Spaces, tabs and line breaks |
| Version | Three numbers, major.minor.patch, such as 3.12.15 |
| Terminal | A window on your own computer where you type commands |
Sources
- Python core developers, PEP 762, "REPL-acing the default REPL", 2024. https://peps.python.org/pep-0762/
- Python Software Foundation, "What's New In Python 3.13", 2024. https://docs.python.org/3/whatsnew/3.13.html
- Python Software Foundation, Python tutorial, "Using the Python Interpreter" (Python 3.12 documentation). https://docs.python.org/3.12/tutorial/interpreter.html
- Python Software Foundation, The Python Language Reference, "Lexical analysis: Indentation" (Python 3.12 documentation). https://docs.python.org/3.12/reference/lexical_analysis.html#indentation
- Guido van Rossum, Barry Warsaw and Alyssa Coghlan, PEP 8, "Style Guide for Python Code", 2001. https://peps.python.org/pep-0008/