import math
pastries = 130
per_crate = 48
crates = math.ceil(pastries / per_crate) # ceil = round UP
print(crates)3
Programming with Python
Pens down. The checkpoint is over. On to Episode 6.
. . .
An hour ago the investor walked into the shop unannounced. It’s due-diligence week: before she signs anything, she wants to see how this place actually runs. Tobi offered her a coffee and a spreadsheet he “mostly trusts.”
. . .
She didn’t drink the coffee. She walked to the whiteboard, uncapped a marker, and wrote one question:
“Why is everything built from scratch?”
For five sessions you built everything by hand, on purpose. From today, that changes.
. . .
For five sessions you worked without AI. From today you may use it, and you stay responsible for every line you hand in.
Both are free, both are on the AI Tools page, together about ten minutes:
. . .
Turn off the training-data switches in Mistral’s privacy settings before you paste coursework: one for Le Chat, one for the API (details on the AI Tools page). Nothing here needs a credit card.
The investor’s question has an answer: you shouldn’t build it from scratch. Most of what you need is already written.
import a module, then reach for the tools inside it with a dot: math.ceil(...). . .
Tobi has been hand-rolling arithmetic for months. The standard library did most of it before he was born.
import math: stop rounding by hand130 pastries need to ship. They go in crates of 48. How many crates? You need to round up: a half-full crate still ships as a whole one.
import math
pastries = 130
per_crate = 48
crates = math.ceil(pastries / per_crate) # ceil = round UP
print(crates)3
. . .
130 / 48 is 2.7…; math.ceil bumps it to 3. No fiddling with “if there’s a remainder, add one.” The tool already knows.
from statistics import ...Sometimes you only want a couple of tools, not the whole box. Import them by name and use them directly, no statistics. prefix:
from statistics import mean, median
ratings = [4.5, 4.8, 1.0, 5.0, 4.2]
print(mean(ratings)) # the average
print(median(ratings)) # the middle value3.9
4.5
. . .
One furious review (a 1.0) drags the mean down to 3.9. The investor asked for the typical rating: median sorts the values and hands back the middle one (4.5), unmoved by one angry customer.
random toolboxThe investor wants to see how the shop copes with a busy day, but the busy day hasn’t happened yet. So we rehearse it with made-up numbers. The random module deals them:
import random
print(random.random()) # a float in [0.0, 1.0)
print(random.randint(1, 20)) # an integer 1-20, ends included
print(random.choice(["latte", "mocha", "tea"])) # one item, picked at random
queue = [1, 2, 3, 4, 5]
random.shuffle(queue) # reorders the list in place
print(queue)0.6780447051994066
8
mocha
[2, 3, 5, 4, 1]
. . .
Four tools, four flavors of luck: a raw float, a bounded integer, a pick from a list, and a reshuffle.
The investor leans over and says: “Run it again.” Tobi does, and gets completely different numbers:
import random
print([random.randint(1, 20) for _ in range(5)]) # _ : a loop name we never use
print([random.randint(1, 20) for _ in range(5)]) # ...and again, different![17, 2, 13, 8, 14]
[3, 13, 10, 11, 12]
. . .
Two runs, two answers. That’s exactly what random is supposed to do, but it’s useless for due diligence. A projection nobody can reproduce is a projection nobody can trust.
random.seed makes luck repeatablerandom.seed(n) fixes the starting point of the number stream. Same seed → same sequence, every time:
import random
random.seed(7)
print([random.randint(1, 20) for _ in range(5)]) # → [11, 5, 13, 2, 3]
random.seed(7)
print([random.randint(1, 20) for _ in range(5)]) # same seed → same list[11, 5, 13, 2, 3]
[11, 5, 13, 2, 3]
. . .
Both lines print [11, 5, 13, 2, 3]. The numbers still look random, but now the investor can run it herself and land on the identical result.
The busiest day needs an extra rider. Tobi seeds, picks one, then seeds again with the same number and picks again. Is it the same rider?
import random
riders = ["Ana", "Ben", "Cem", "Dana"]
random.seed(3)
first = random.choice(riders)
random.seed(3)
second = random.choice(riders)
print(first == second)a) False: choice picks freely, the seed only steers randint b) True: same seed, same stream, same pick c) an error: a seed can only be set once per program
. . .
Predict first. Pick a letter, then I reveal the answer.
b) True. Every random tool draws from the same stream, and re-seeding rewinds it to the start. choice is no exception: after seed(3) it lands on the same item every time:
import random
riders = ["Ana", "Ben", "Cem", "Dana"]
random.seed(3)
first = random.choice(riders)
random.seed(3)
second = random.choice(riders)
print(first == second)
print(first, second) # Ben Ben: the seed makes every tool in the box repeatableTrue
Ben Ben
Tobi seeds once, then builds two lists the same way, without touching the seed in between. Are first and second equal?
import random
random.seed(42)
first = [random.randint(1, 20) for _ in range(3)]
second = [random.randint(1, 20) for _ in range(3)]
print(first)
print(second)a) different: the second list continues where the first stopped b) equal: the seed is set, so both come out the same c) an error: the stream is empty after three draws
. . .
Predict first. Pick a letter, then I reveal the answer.
a) different. A seed doesn’t freeze random, it fixes the whole sequence. The first list eats the first three numbers of the stream; the second list simply continues from number four:
import random
random.seed(42)
first = [random.randint(1, 20) for _ in range(3)]
second = [random.randint(1, 20) for _ in range(3)]
print(first) # [4, 1, 9]: the stream's first three numbers
print(second) # [8, 8, 5]: the stream carries on[4, 1, 9]
[8, 8, 5]
. . .
To get the same list twice, you re-seed before each run, and that rewinds the stream to the start. One seed, one fixed sequence: that’s the entire job of a seed.
import math and statistics for investor-grade counts and averages, then use random with a seed to rehearse a busy day she can reproduce. . .
Download your .py before you leave. Closing the tab without downloading loses your work, and downloading is exactly how you handed in the checkpoint at the start of the session.
import math, from statistics import median, import ... as for a nickname. dir() and help() show you what’s inside.random deals the luck (random(), randint, choice, shuffle), perfect for rehearsing a day that hasn’t happened yet.random.seed(n) makes luck repeatable. Same seed → same sequence, every run. A projection you can reproduce is a projection an investor can trust.. . .
Next episode: the numbers deck. The shop’s data has outgrown plain lists, and NumPy turns a thousand numbers into a single, fast object.
. . .
New this session: the AI Tools page: how and when to use AI in Part II, and the one-line disclosure habit that goes on every submission from here on.
. . .
For more, see the literature list of this course.