Python Cheatsheet

pep8 = bible

Numerical Work: Use NumPy by Default

For this course, use NumPy for most numerical calculations.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import numpy as np

np.sqrt(9)           # → 3.0
np.sqrt(-1 + 0j)     # → 1j; use complex input
np.pi
np.exp(1)
np.log(10)           # natural logarithm
np.sin(np.pi / 2)

# The same functions work element-wise on arrays
x = np.array([1.0, 4.0, 9.0])
np.sqrt(x)           # → array([1., 2., 3.])

You generally won’t need the math or cmath modules in this course.


REPL & Package Management

Python’s standard REPL has no separate package or shell modes.

WhereCommandPurpose
TerminalpythonStart Python
Pythonhelp(str)Documentation
Pythondir(str)List attributes and methods
Pythonexit()Exit
Terminalpython script.pyRun a file
Terminalpython -m pip install numpyInstall a package
Terminalpython -m pip listList installed packages
Terminalpython -m pip uninstall numpyRemove a package

On some systems, use python3 instead of python.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Create a project environment
python -m venv .venv

# Activate: macOS / Linux
source .venv/bin/activate

# Activate: Windows PowerShell
.venv\Scripts\Activate.ps1

# Install packages used below
python -m pip install numpy pandas matplotlib

# Deactivate the environment
deactivate

Variables & Types

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
x = 55699             # int
x = 1 + 1j            # complex
x = 3.14              # float
x = True              # bool: True / False
x = None              # absence of a value

type(x)               # check type
isinstance(x, float)  # check whether x is a float

int("42")             # string → integer
float("3.14")         # string → float
str(42)               # integer → string

For NumPy arrays:

1
2
3
4
5
6
7
import numpy as np

v = np.array([1, 2, 3], dtype=float)
v.dtype               # element type
v.shape               # → (3,)
v.ndim                # number of dimensions → 1
v.size                # total element count → 3

Arithmetic & Math

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import numpy as np

2 ** 3                # exponent → 8 (not ^)
8 / 5                 # true division → 1.6
8 // 5                # floor division → 1
-8 // 5               # → -2: rounds down
8 % 5                 # modulo → 3

np.sqrt(9)            # → 3.0
np.sqrt(-1 + 0j)      # → 1j
abs(-3)               # → 3
np.abs(-3)            # also works on arrays
round(3.14159, 2)     # → 3.14

np.pi
np.exp(1)
np.log(10)            # natural logarithm
np.log10(100)         # → 2.0
np.sin(np.pi / 2)
np.cos(0)

# Comparisons and logic for individual values
x = 3
y = 5

x == y                # equality
x != y                # inequality
x > 0 and x < 10
0 < x < 10            # chained comparison
x < 0 or x > 10
not True              # → False
x is None             # identity check for None

For NumPy arrays, use element-wise logical operators:

1
2
3
4
5
6
7
8
v = np.array([-1, 2, 12])

(v > 0) & (v < 10)   # element-wise AND
(v < 0) | (v > 10)   # element-wise OR
~(v > 0)              # element-wise NOT

np.any(v > 0)         # is at least one element positive?
np.all(v > 0)         # are all elements positive?

Use parentheses around each comparison when combining conditions with & or |.


Strings

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
s = "hello"

f"{s} world"          # interpolation
s + "!"               # concatenation
len(s)
s.upper()
"a b c".split()       # → ["a", "b", "c"]
", ".join(["a", "b"]) # → "a, b"
"  hello  ".strip()   # → "hello"
s.replace("h", "H")

s[0]                  # first character
s[-1]                 # last character
s[1:4]                # → "ell"; stop index excluded

f"{3.14159:.2f}"      # → "3.14"

Strings are immutable: s[0] = "H" raises an error.


Functions

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# Anonymous function: a single expression
double = lambda x: 2 * x

# Full form: preferred for non-trivial logic
def square(x):
    return x ** 2

square(2)             # → 4

# Optional positional arguments + keyword-only arguments
def f(x, y=2, z=3, *, a=4.0, b=5.0):
    print([x, y, z, a, b])
    return x + y + z ** a + b

f(1)
f(1, 10, b=173, a=77)
f(1, 2, 4, b=173)

# Unpack a dictionary as keyword arguments
opts = {"a": 5.0, "b": 3.0}
f(1, 2, 4, **opts)

# Unpack positional arguments
args = (1, 2, 4)
f(*args, **opts)

# Accept any number of positional arguments
def total(*values):
    return sum(values)

total(1, 2, 3)        # → 6

# Type hints: documentation, not runtime enforcement
def cube(x: float) -> float:
    return x ** 3

Indentation defines blocks—normally four spaces. There is no end.

Avoid mutable defaults such as items=[]; use None and create the list inside the function.

Element-wise functions

1
2
3
4
5
6
7
import numpy as np

v = np.array([1.0, 2.0, 3.0])

square(v)             # works because NumPy supports v ** 2
np.sin(v)             # element-wise sine
np.sin(v) ** 2

A function works on arrays directly only if its operations support arrays. Otherwise, use a comprehension:

1
results = [f(x) for x in v]

Control Flow

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
x = 3

if x > 0:
    print("positive")
elif x == 0:
    print("zero")
else:
    print("negative")

# Conditional expression
label = "pos" if x > 0 else "non-pos"

# for loop: stop value excluded
for i in range(1, 6):
    print(i)           # 1 through 5

# while loop
i = 1
while i <= 5:
    i += 1

# break / continue
for i in range(10):
    if i == 2:
        continue
    if i == 5:
        break

# Error handling
try:
    n = int("hello")
except ValueError:
    print("Not an integer")

Lists, Tuples, Dictionaries & Sets

Lists

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# List: mutable sequence
v = [1, 2, 3]

v.append(4)           # append one value
v.extend([5, 6])      # append multiple values
last = v.pop()        # remove and return last value

len(v)
sum(v)
max(v)
min(v)

sorted(v)            # return a sorted copy
v.sort()             # sort in place; returns None

# Concatenation
[1, 2] + [3, 4]      # → [1, 2, 3, 4]

# Indexing: zero-based; slice stop excluded
v[0]                 # first element
v[-1]                # last element
v[1:4]               # elements at indices 1, 2, 3
v[1:]                # from second element onward
v[::2]               # every second element
v[::-1]              # reversed copy

Use NumPy arrays for numerical arithmetic. Lists behave differently:

1
2
[1, 2] * 2                      # → [1, 2, 1, 2]
np.array([1, 2]) * 2            # → array([2, 4])

Tuples, dictionaries & sets

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# Tuple: immutable sequence
point = (2, 3)
x, y = point         # unpacking
single = (2,)        # one-element tuple needs a comma

# Dictionary: key → value
params = {"a": 4.0, "b": 5.0}

params["a"]
params["c"] = 6.0
params.get("missing", 0)

for key, value in params.items():
    print(key, value)

# Set: unique elements
values = {1, 2, 2, 3} # → {1, 2, 3}
values.add(4)
2 in values          # → True
empty_set = set()    # {} creates an empty dictionary

Ranges, comprehensions & iteration

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
r = range(1, 11)     # lazy range: 1 through 10
range(0, 10, 2)      # 0, 2, 4, 6, 8

arr = [x ** 2 for x in range(1, 11)]
gen = (x ** 2 for x in range(1, 11))  # lazy generator
list(gen)            # materialize; consumes the generator

evens = [x for x in range(10) if x % 2 == 0]

# Iterate over values directly
v = [1, 2, 3]

for value in v:
    print(value)

# Index and value
for i, value in enumerate(v):
    print(f"v[{i}] = {value}")

# Iterate two sequences together
w = [10, 20, 30]

for a, b in zip(v, w):
    print(a + b)      # zip stops at the shorter sequence

Numerical Arrays — NumPy

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import numpy as np

v = np.array([1, 2, 3], dtype=float)

# Constructors
np.zeros(3)
np.ones(3)
np.full(3, np.pi)
np.empty(3)           # uninitialized values

# Random numbers
rng = np.random.default_rng(42)  # seed for reproducibility
rng.random(5)         # uniform [0, 1)
rng.standard_normal(5)

# Ranges
np.arange(1, 11)      # 1 through 10
np.arange(0, 1, 0.1)  # stop excluded; floating-point steps
np.linspace(0, 1, 50) # 50 points, both endpoints included

# Element-wise arithmetic
v ** 2
np.sin(v) ** 4
v + 10
v * v

# Reductions
v.sum()
v.prod()
v.max()
v.min()
v.mean()
v.std()               # population standard deviation by default

# Indexing
v[0]                  # first element
v[-1]                 # last element
v[1:3]                # second and third elements

# Filtering
v[v > 1]

# Modify in place
v *= 2
v.fill(np.pi)

Copies & views

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
v = np.array([1.0, 2.0, 3.0])

# Basic slices usually share the original data
part = v[1:]
part[0] = 99          # also changes v

# Explicit independent copy
independent = v[1:].copy()

# Assignment shares the same object
alias = v
independent = v.copy()

Matrices — NumPy

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import numpy as np

A = np.array([[1, 2, 3],
              [4, 5, 6]])       # shape (2, 3)

# Reshape: default order fills rows first
np.arange(1, 10).reshape(3, 3)

# Julia-style column-first order
np.arange(1, 10).reshape(3, 3, order="F")

# Constructors
np.zeros((3, 3))
np.ones((2, 4))
np.empty((3, 3))                # uninitialized values
np.eye(3)                       # identity matrix

rng = np.random.default_rng(42)
rng.random((3, 3))
rng.standard_normal((3, 3))

# Indexing: zero-based
A[0, 1]                         # first row, second column
A[:, 0]                         # first column
A[0, :]                         # first row

# Row / column arrays
v = np.array([1, 2, 3])
row = v[None, :]                # shape (1, 3)
col = v[:, None]                # shape (3, 1)

# Transposing a 1D array does not make it a column
v.T.shape                       # still (3,)

# Concatenation
np.vstack((A, A))               # stack rows
np.hstack((A, A))               # join columns

# Transpose
A.T                             # ordinary transpose
A.conj().T                      # conjugate transpose

Linear algebra

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
A = np.array([[3.0, 1.0],
              [1.0, 2.0]])
B = np.eye(2)
b = np.array([9.0, 8.0])

A @ B                           # matrix multiplication
A * B                           # element-wise multiplication

np.linalg.inv(A)
np.trace(A)
np.diag(A)
np.linalg.det(A)
np.linalg.norm(A)

values, vectors = np.linalg.eig(A)
np.linalg.eigvals(A)
U, s, Vh = np.linalg.svd(A)

# Solve A @ x = b
x = np.linalg.solve(A, b)        # prefer over inv(A) @ b

Broadcasting

1
2
3
4
5
6
A = np.ones((2, 3))
v = np.array([10, 20, 30])

A + v                           # adds v to every row
A.sum(axis=0)                   # sum over rows → shape (3,)
A.sum(axis=1)                   # sum over columns → shape (2,)

Dimensions are compatible when they match or one is 1, comparing from the right.


Summation Patterns

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import numpy as np

N = 10

# Loop
result = 0.0
for i in range(1, N + 1):
    result += 1 / i ** 2

# List comprehension
result = sum([1 / i ** 2 for i in range(1, N + 1)])

# Generator: no intermediate list
result = sum(1 / i ** 2 for i in range(1, N + 1))

# NumPy: convenient for numerical arrays
i = np.arange(1, N + 1, dtype=float)
result = np.sum(1 / i ** 2)

Recursion

1
2
3
4
5
6
def fac(n: int) -> int:
    if n < 0:
        raise ValueError("n must be non-negative")
    return 1 if n == 0 else n * fac(n - 1)

fac(5)                          # → 120

This function expects a non-negative integer. Type hints do not validate inputs at runtime.

Python limits recursion depth; use loops or library functions for large inputs.


I/O

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# User input
s = input("Text: ")
x = float(input("Number: "))
n = int(input("Integer: "))

# Output
print("hello")
print(f"x = {x:.3f}")

# "w" overwrites; with closes the file automatically
with open("notes.txt", "w", encoding="utf-8") as file:
    file.write("hello\n")

with open("notes.txt", encoding="utf-8") as file:
    text = file.read()

Numerical text files

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import numpy as np

# Example: solver returns two real numbers per x
def solver(x):
    return np.sin(x), np.cos(x)

x_arr = np.linspace(0, 1, 10)

# Rows = samples; columns = x plus two solver outputs
data = np.zeros((len(x_arr), 3))

for i, x_now in enumerate(x_arr):
    data[i, :] = [x_now, *solver(x_now)]

# Header automatically starts with "# "
np.savetxt("result.dat", data, delimiter="\t", header="x\ty\tz")

data2 = np.loadtxt("result.dat", delimiter="\t", comments="#")
xvec = data2[:, 0]
yvec = data2[:, 1]
zvec = data2[:, 2]

# Alternative: calculate all samples at once
yvec, zvec = solver(x_arr)
data = np.column_stack((x_arr, yvec, zvec))

CSV & DataFrames — pandas

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import pandas as pd

# Named columns in an ordinary CSV
df = pd.DataFrame({"x": xvec, "y": yvec, "z": zvec})
df.to_csv("result.csv", index=False)

df2 = pd.read_csv("result.csv")

# Read the tab-delimited file above
df3 = pd.read_csv(
    "result.dat",
    sep="\t",
    comment="#",
    header=None,
    names=["x", "y", "z"],
)

df["x"]                         # one column
df.head()                       # first five rows
df["x"].to_numpy()              # column → NumPy array

Load another Python file

1
2
3
4
5
6
7
# For a local file named myfile.py
import myfile
from myfile import solver

# Code that runs only when this file is executed directly
if __name__ == "__main__":
    print("Running as a script")

Plotting — Matplotlib

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2 * np.pi, 200)

fig, ax = plt.subplots()
ax.plot(x, np.sin(x), label="sin(x)", linewidth=2)
ax.plot(x, np.cos(x), label="cos(x)", linestyle="--")

ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_title("Trig functions")
ax.legend()

fig.tight_layout()
fig.savefig("fig.png", dpi=300)  # also .pdf or .svg
plt.show()

Introspection & Performance

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import inspect
import timeit
import cProfile
import dis

def square(x):
    return x ** 2

help(square)
dir(square)
inspect.signature(square)
inspect.getsource(square)      # requires available source
dis.dis(square)                # Python bytecode

# Average time per call across 10,000 calls
elapsed = timeit.timeit(lambda: square(10), number=10_000)
print(elapsed / 10_000)

# Profile a workload
cProfile.run("sum(i ** 2 for i in range(100_000))")

In IPython / Jupyter only:

1
2
3
4
5
square?                        # help
square??                       # source, when available
%timeit square(10)             # repeated timing
%run script.py                 # run a script
%pip install numpy             # install into current environment

Key Differences from Julia

JuliaPython
true, false, nothingTrue, False, None
x^2x ** 2
1im1j
First index: 1First index: 0
1:5 includes 5range(1, 6) includes 5
v[end]v[-1]
length(v)len(v)
push!(v, x)v.append(x) for a list
f.(v)Array-compatible function or comprehension
A * B matrix productA @ B for NumPy arrays
A .* BA * B for NumPy arrays
A'A.conj().T
A \ bnp.linalg.solve(A, b)
using Fooimport foo
Blocks end with endBlocks use indentation

Remember: Python slices exclude the stop index, and basic NumPy slices usually return views that share the original data.


Further Resources