Python Basics
A refresher on the language itself. Assumes you have Python installed and can run code — see Setup and Workflows — but no prior Python experience.
Enough Python to do lab work: values, functions, loops, and imports. If you’ve programmed before in any language, skim this and move on. If you haven’t, work through it once and come back when something doesn’t behave.
This is a floor, not a course. For depth, the official Python tutorial is genuinely good.
1 Values and variables
A variable is a name for a value. Python works out the type; you don’t declare it.
wavelength = 632.8 # float — a decimal number
n_samples = 100 # int — a whole number
filename = "run3.csv" # str — text
is_saturated = False # bool — True or FalseThe distinction that bites most often is int vs float. Division always gives a float, but some operations care:
7 / 2 # 3.5 — true division
7 // 2 # 3 — floor division, discards the remainder
7 % 2 # 1 — remainder
2 ** 10 # 1024 — exponent (not ^, which is something else entirely)^ is not exponentiation
In Python, ^ is bitwise XOR. Writing 2^10 gives you 8, silently and with no error. Use **.
2 Printing results
Use an f-string — a string prefixed with f, with expressions in braces:
resistance = 98.437
print(f"R = {resistance} ohms") # R = 98.437 ohms
print(f"R = {resistance:.1f} ohms") # R = 98.4 ohms
print(f"R = {resistance:.2e} ohms") # R = 9.84e+01 ohmsThe :.1f part is a format specifier: .1f means one decimal place, .2e means scientific notation with two. Report numbers to a sensible precision rather than dumping every digit Python has.
3 Functions
A function packages a calculation so you can run it again with different inputs. This matters more in lab work than it might seem — see Working Effectively for why.
def photon_energy(wavelength_nm):
"""Return photon energy in joules for a wavelength in nanometres."""
h = 6.626e-34 # Planck constant, J·s
c = 2.998e8 # speed of light, m/s
return h * c / (wavelength_nm * 1e-9)
energy = photon_energy(632.8)
print(f"{energy:.3e} J")Three things to notice:
defstarts the definition; the indented block is the body. Indentation is syntax in Python, not decoration.returnhands a value back. A function with noreturngives youNone, which is a common source of confusion when a calculation silently produces nothing.- The string on the first line is a docstring. Optional, but it’s how you’ll remember what the function expects when you reuse it three weeks later.
Arguments can have defaults, which lets you call a function without repeating what usually doesn’t change:
def voltage_divider(v_in, r1, r2=1000.0):
"""Output voltage of a two-resistor divider. r2 defaults to 1 kΩ."""
return v_in * r2 / (r1 + r2)
voltage_divider(5.0, 2200) # uses r2 = 1000
voltage_divider(5.0, 2200, r2=4700) # overrides it4 Lists
An ordered, changeable collection:
voltages = [0.1, 0.5, 1.2, 2.4]
voltages[0] # 0.1 — first element (counting starts at zero)
voltages[-1] # 2.4 — last element
voltages[1:3] # [0.5, 1.2] — a slice: from index 1 up to but not including 3
len(voltages) # 4
voltages.append(3.0) # add to the endLists are fine for a handful of values. For numerical work — arrays of measurements you want to do arithmetic on — use NumPy arrays instead; see Arrays and Plotting.
5 Loops
A for loop runs a block once per item:
for v in [0.1, 0.5, 1.2]:
print(f"{v} V -> {v / 50:.4f} A")range(n) gives you the whole numbers from 0 to n−1, which is how you loop a fixed number of times:
for i in range(5):
print(i) # 0 1 2 3 4To loop over items and know their position, use enumerate:
for i, v in enumerate(voltages):
print(f"point {i}: {v} V")6 Conditionals
if voltage > 10:
print("Over range — reduce the input.")
elif voltage > 9:
print("Approaching full scale.")
else:
print("Fine.")Comparisons: == (equal), != (not equal), <, >, <=, >=. Combine with and, or, not.
= assigns, == compares
x = 5 sets x to 5. x == 5 asks whether it already is. Using = where you meant == is a syntax error inside an if, which is the good outcome — the bad one is using == where you meant = and wondering why nothing changed.
Comparing floats for exact equality is unreliable, because floating-point arithmetic carries small rounding errors:
0.1 + 0.2 == 0.3 # False
abs((0.1 + 0.2) - 0.3) < 1e-9 # True — compare within a tolerance7 Imports
Most of what you’ll use lives in packages you import at the top of the file:
import numpy as np # whole package, under a short alias
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit # one specific functionThe as np / as plt aliases are near-universal conventions. Follow them — every example you’ll find online assumes them, including the ones on this site.
8 When something goes wrong
Python errors name the problem on the last line. The four you’ll meet first:
| Error | What it usually means |
|---|---|
NameError: name 'x' is not defined |
Typo, or you’re using a variable before setting it — or you edited a cell and didn’t re-run it |
IndentationError / TabError |
Inconsistent indentation. Use spaces, not tabs; your editor can enforce this |
TypeError: unsupported operand type(s) |
Mixing incompatible types, often a string where a number belongs |
ModuleNotFoundError: No module named 'numpy' |
The package isn’t installed, or the editor is pointed at a different Python — see Setup |
Read the last line first. The traceback above it shows how execution got there, which matters once your code spans several functions.