Stage 2 of 6 · Theory, hands on the REPL · about 30 minutes
Python from zero
Every program you will write this semester, up to the term project's control logic, is built from four moves: store values, decide, repeat, and name recipes. This page introduces all four, small enough to try each one as you read.
What a program is
A program is a text file of instructions that a machine performs exactly and in order. The machine here is the interpreter, a program named python3 that reads your file top to bottom and does what each line says: compute a value, print text, wait, or, from the First light page on, pull a GPIO pin high.
Coming from ladder logic, one difference deserves naming: a PLC scan loops over all rungs continuously by itself. A Python script runs once, top to bottom, then exits, unless you write the loop yourself. The "scan cycle" of your IoT programs will be a while loop you can see and control, which is why loops get their own section below.
Two ways to run Python
The REPL · for trying things
Type python3 alone and you get the >>> prompt: Read, Evaluate, Print, Loop. Each line runs immediately and shows its result. It is a calculator, an experiment bench, and the fastest way to answer "what does this do?". Quit with exit() or Ctrl+D.
Scripts · for keeping work
Write the same lines into a file with nano hello.py, run it with python3 hello.py. Scripts are repeatable, committable and gradeable; every hand-in from now on is a script in your repository. Rule of thumb: explore in the REPL, keep in a script.
$ python3
Python 3.11.2 (main, ...) on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 3.3 - 2.0
1.2999999999999998
>>> (3.3 - 2.0) / 330 # the LED current calculation from the GPIO page, in amps
0.00393939393939394
>>> exit()
About that 1.2999999999999998
Computers store decimals in binary, and most decimal fractions have no exact binary form, so tiny rounding appears. It is universal to floating-point arithmetic, not a Python bug, and it is why measurement code compares with tolerances ("within 0.01") rather than exact equality. File the fact away; it returns with sensor readings.
Variables and types
A variable is a name attached to a value. Naming values is how programs stay readable and changeable: alter delay once and every use follows.
>>> delay = 0.5 # a float (decimal number)
>>> blinks = 10 # an int (whole number)
>>> name = "lastname-pi" # a str (text, in quotes)
>>> running = True # a bool: True or False, capitalized
>>> blinks * delay
5.0
>>> print(f"{name} will blink {blinks} times")
lastname-pi will blink 10 times
=means assign, "attach this name to this value", not mathematical equality. (Equality testing is==, next section.)- The main types this course uses:
int,float,str,bool.type(delay)tells you what you have. print()writes to the terminal; anf"..."string with{name}inside splices values into text. You will format every sensor reading this way.- Names: lowercase with underscores (
press_count), chosen to make the code read like the Week 5 pseudocode it came from.
Decisions: if and else
temperature = 31.5
if temperature > 30:
print("Too hot, fan on")
elif temperature < 18:
print("Too cold, heater on")
else:
print("In range")
Three things to absorb, because every control program is made of them:
- The condition (
temperature > 30) is an expression that evaluates toTrueorFalse. Comparisons:><>=<===(equals)!=(not equals); combine withand,or,not. - The colon and the indent define the block: everything indented under the
ifbelongs to it. This is the thermostat logic of Assignment 2 in miniature. elifchains further tests;elsecatches everything remaining. At most one branch runs.
Indentation is grammar, not decoration
In Python the indent is the block structure: four spaces per level, consistently. Mixing widths, or mixing tabs and spaces, produces IndentationError or, worse, code that runs but does the wrong thing because a line sits outside the block you meant. nano on the Pi and every serious editor insert spaces for you; when a block ends, unindent back to the previous level. If a program misbehaves, checking the indentation is step one.
Repetition: while and for
while · repeat as long as
from time import sleep
count = 0
while count < 5:
print(f"blink {count}")
sleep(0.5)
count = count + 1
Runs while the condition stays true. while True: runs forever, and that is not a mistake: it is the scan cycle of every monitoring program you will write. Stop a running script with Ctrl+C.
for · repeat for each
for count in range(5):
print(f"blink {count}")
for colour in ["red", "green", "blue"]:
print(colour)
Walks through a sequence: range(5) yields 0,1,2,3,4; a list in square brackets yields its items. Use for when the collection or count is known, while when a condition decides.
The sleep() call comes from the time module via an import: from time import sleep at the top of the file makes the function available. Imports are how all borrowed code arrives, including gpiozero two pages from now; the Environments page explains where imported code actually lives.
Functions: naming a recipe
from time import sleep
def blink_message(times, delay):
"""Print a blink message 'times' times, 'delay' seconds apart."""
for n in range(times):
print(f"blink {n}")
sleep(delay)
blink_message(3, 0.5) # fast
blink_message(2, 1.0) # slow
A function wraps a block under a name, with parameters for the parts that vary. Defining it does nothing; calling it runs it. Functions are how programs stop being one long scroll: the same recipe, reused with different values, testable on its own. A function can also return a value to its caller (def celsius(raw): return raw * 0.1), which is how sensor-reading code will hand you numbers. Week 6 builds classes out of exactly this idea.
Tracebacks: errors that explain themselves
You will cause errors today, on purpose and otherwise. Python reports them with a traceback, and like Git's messages in Week 1, it is written to be read:
$ python3 blink.py
Traceback (most recent call last):
File "/home/username/iot/week4/blink.py", line 4, in <module>
print(f"blink {countt}")
^^^^^^
NameError: name 'countt' is not defined. Did you mean: 'count'?
- Read from the bottom. The last line is the diagnosis: the error type (
NameError) and the explanation, here with the fix suggested. - The lines above give the address: file and line number. Open the file at that line; the answer is almost always there or one line earlier.
- The frequent ones this week:
SyntaxError(typo in the grammar, often a missing colon or quote),IndentationError(see the stop box above),NameError(misspelled name, or used before assignment),ModuleNotFoundError(import failed, an environment question, not a code one).
Read more, practise more
The official Python tutorial covers this page's material in chapters 1 to 4, in the language's own words. For a gentler second telling with projects, the free book Automate the Boring Stuff with Python is the classic; its first chapters map onto today exactly. Both are linked with the other references on the Resources page.
Checklist for this stage
Check yourself
What does the interpreter do with a script, and how is that different from a PLC scan?
while loop you write explicitly.When do you reach for the REPL, and when for a script?
What is the difference between = and ==?
= assigns: attach a name to a value. == compares: evaluate to True or False. Writing if x = 5: is a SyntaxError precisely to catch this mix-up.Why is while True: legitimate in this course's programs?
A traceback fills the screen. Which line do you read first, and what do the others give you?
Defining a function ran no code. Why not, and what does?
def only records the recipe under a name. Calling it, blink_message(3, 0.5), runs it, with the arguments filling the parameters. One definition, many calls, is the whole point.