Learning Goals
3 minBy the end of this lesson you can:
- Build a complete interactive spinner with
input(),random.choice()and awhile Trueloop. - Use
random.shuffle()correctly — knowing it changes the list in place and returnsNone. - Weight a random pick by repeating popular items inside the list (a sneaky preview of probability).
Warm-Up
5 minPicture the food court at SS15. Twelve stalls, all tempting, and three friends arguing for ten minutes about what to order. The deciding tool everyone reaches for? A spinner. A coin. A finger-pointing game. Tonight we make Python the deciding tool.
Predict-the-output. What does this print?
import random menu = ["nasi lemak", "char kuey teow", "roti canai"] print("Tonight's makan:", random.choice(menu))
Show one possible answer
Tonight's makan: char kuey teow
Could be any of the three. The whole spinner-game we're about to build is dressing on that single line — random.choice(menu).
Last lesson we made the player type something. Tonight, the player just presses Enter — no question, no typing, just "decide for me". We'll also meet random.shuffle(), which has a famously sneaky behaviour: it doesn't hand back a shuffled list. It changes the list in place.
New Concept · choice vs shuffle
10 minRefresher · random.choice()
You met this in PY-L1-19 and used it again in PY-L1-20. Given a list, it returns one item, picked at random:
import random menu = ["mee goreng", "satay", "char kuey teow"] print(random.choice(menu)) # → e.g. "satay"
The list itself is unchanged afterward — menu still has all three items in their original order.
New · random.shuffle() — the in-place rearranger
random.shuffle() shuffles a list in place. That means it reaches into the list itself and rearranges it. It does not hand a new list back — it gives back None, which is Python's way of saying "nothing to see here".
import random menu = ["mee goreng", "satay", "char kuey teow"] random.shuffle(menu) print(menu) # → ['char kuey teow', 'mee goreng', 'satay'] (some order)
Notice we call random.shuffle(menu) on its own line and then look at menu — the list has been rearranged.
This looks reasonable but destroys your menu:
menu = random.shuffle(menu) # ⚠️ wrong print(menu) # → None
random.shuffle returns None, so you just overwrote menu with None. The list is gone. Rule of thumb: methods that change things in place return None. Call them on their own line. You'll see this exact pattern again with .sort(), .append(), and .reverse().
choice or shuffle — which to use?
- Just want one winner? Use
random.choice(menu). The menu stays intact. - Want the whole list in random order — for a draw, a queue, a rota? Use
random.shuffle(menu), then loop overmenuin its new order.
Worked Example · Build the Picker
18 minFive phases tonight. Save as lucky_draw.py and build it in order — don't skip ahead.
Phase 1 · A one-shot spinner
Code
# lucky_draw.py — Lucky Draw Picker (Phase 1 of 5) import random menu = [ "nasi lemak", "char kuey teow", "mee goreng", "satay", "roti canai", "wantan mee", "nasi kandar", "asam laksa", "hokkien mee", "lor mee", ] print("Tonight's makan:", random.choice(menu))
Run it. One pick. Run again — different pick. Ten dishes, all very real, all very edible. Notice we kept the list intact for next time.
Phase 2 · A Press-Enter spinner loop
The player shouldn't need to type anything to spin — just hit Enter. We'll let any input that isn't the word quit count as "spin again".
Code (replace the single print line)
print("Welcome to the Lucky Draw food picker.") print("Press Enter to spin, or type 'quit' to leave.") while True: spin = input("\nSpin? ") if spin.lower() == "quit": break print("Tonight's makan:", random.choice(menu)) print("Selamat makan!")
Run it. Press Enter four or five times — you'll see a dish each time. Type quit and you get the goodbye line. Notice that pressing Enter alone makes spin the empty string "", which isn't "quit", so the loop happily spins on.
Phase 3 · Shuffle the menu first (the right way)
Some players want the "shuffle the menu first" feel — like a real lucky-draw machine that gets visibly tumbled before the first pick. We do that once, at the top, before the loop.
Code (add just under the menu = [...] block)
# Tumble the menu once at startup. shuffle changes the list # in place and returns None — do NOT write menu = random.shuffle(menu). random.shuffle(menu) print("Menu has been shuffled.") print(menu)
Run the program and you should see the ten dishes in a new order each time you start. random.choice inside the loop is still doing the per-spin pick — the shuffle just changes the order they're stored in, not the per-spin randomness.
Phase 4 · See the trap up close
Let's deliberately do it the wrong way, see what happens, then fix it. Temporarily add this after the shuffle:
Code (the wrong way — for learning only)
menu = random.shuffle(menu) # ⚠️ wrong on purpose print("menu is now:", menu)
Output
menu is now: None
Run the rest of the program now and the next random.choice(menu) will crash with TypeError: 'NoneType' object is not subscriptable — because menu is no longer a list. Delete those two wrong lines once you've seen the error. Lesson learned: call shuffle on its own line.
Phase 5 · Weighted picks — make satay more likely
Suppose the class agreed that satay should win more often because everyone loves it. We don't need any new tool — just repeat "satay" three times in the list. random.choice picks uniformly from the list, so an item that appears 3× has 3× the chance.
Full file
# lucky_draw.py — Lucky Draw Picker (Phase 5 of 5) import random # Some dishes appear more than once on purpose — that's our weight. menu = [ "nasi lemak", "nasi lemak", "char kuey teow", "mee goreng", "satay", "satay", "satay", "roti canai", "wantan mee", "nasi kandar", "asam laksa", "hokkien mee", "lor mee", ] random.shuffle(menu) # one-time tumble; on its own line! print("Welcome to the Lucky Draw food picker.") print("Press Enter to spin, or type 'quit' to leave.") spins = 0 while True: spin = input("\nSpin? ") if spin.lower() == "quit": break spins = spins + 1 print("Tonight's makan:", random.choice(menu)) print() print("You spun", spins, "times.") print("Selamat makan!")
One sample run (lines you type are bold):
Output
Welcome to the Lucky Draw food picker. Press Enter to spin, or type 'quit' to leave. Spin? <strong></strong> Tonight's makan: satay Spin? <strong></strong> Tonight's makan: nasi lemak Spin? <strong></strong> Tonight's makan: satay Spin? <strong>quit</strong> You spun 3 times. Selamat makan!
What every earlier lesson contributed
- L1-07 ·
input— the "press Enter to spin" prompt. - L1-08 ·
if— the quit check. - L1-12 ·
while True+ counter — the forever loop and thespinstally. - L1-15 · lists — the menu lives in a list, and a repeated item is just a fact about that list.
- L1-19 ·
random.choice&shuffle— the deciders.
Try It Yourself · Extend the Picker
13 minPick at least two of these and add them to lucky_draw.py. Run after each change.
It feels unlucky when the spinner gives you the same dish twice in a row. Track the last dish in a variable last, and if the new pick equals last, pick again with a single re-spin. (Keep it simple — only retry once.)
Hint
last = "" while True: spin = input("\nSpin? ") if spin.lower() == "quit": break pick = random.choice(menu) if pick == last: pick = random.choice(menu) # one re-spin print("Tonight's makan:", pick) last = pick
Start last at "" so the first spin never matches and you don't reroll on round one.
Real lucky-draw machines often show a few finalists before the winner. Each spin: shuffle the menu (in place!), print the first three dishes as "shortlist", then pick the winner from the whole menu with random.choice. Use list slicing (PY-L1-18) for the shortlist.
Hint
random.shuffle(menu) shortlist = menu[0:3] print("Shortlist:", shortlist) print("Winner: ", random.choice(menu))
menu[0:3] grabs items at positions 0, 1, 2 — three dishes. The winner could be one of the three or any other dish; that's fine. (Bonus: try random.choice(shortlist) instead to lock the winner to the shortlist.)
Build a second list called drinks with five mamak drinks ("teh tarik", "kopi-O", "milo ais", "limau ais", "sirap bandung"). Each spin should pick one dish and one drink, and print them as a combo.
Hint
drinks = ["teh tarik", "kopi-O", "milo ais", "limau ais", "sirap bandung"] # inside the while loop: food = random.choice(menu) drink = random.choice(drinks) print("Tonight's combo:", food, "+", drink)
Two independent picks, one combined line. Notice we call random.choice twice — once per list. The food's pick has nothing to do with the drink's pick, which is exactly how a real menu works.
Mini-Challenge · Class Cleaning Rota
8 minMei is the class monitor and she's tired of arguing about whose turn it is to clean the whiteboard. Help her build cleaning_rota.py:
- Start with a list of at least six names:
students = ["Hafiz", "Aisyah", "Daniel", "Priya", "Mei", "Aiman"]. - Use
random.shuffle(students)on its own line. Do not writestudents = random.shuffle(...)— that returnsNoneand ruins the list. - Print a header like
"This week's cleaning rota:". - Use
enumerate(students, start=1)(from PY-L1-16) to print each student numbered1.through6.in the freshly shuffled order. That's the day-by-day rota for the week. - Underneath, use
random.choice(students)to pick a bonus chairperson for the week. Print that name on its own line.
Stretch. Add an input("Press Enter to reshuffle, or 'done': ") loop so Mei can re-roll the rota until she likes it. Use while True + break.
Show one possible solution
# cleaning_rota.py — fairly random class cleaning rota import random students = ["Hafiz", "Aisyah", "Daniel", "Priya", "Mei", "Aiman"] random.shuffle(students) # in place — own line! print("This week's cleaning rota:") for i, name in enumerate(students, start=1): print(i, ".", name) print() print("Bonus chairperson:", random.choice(students))
The two non-negotiables are: random.shuffle(students) on its own line (never students = in front of it), and an enumerate(students, start=1) loop to print the rota. Your names can vary; six or more is the floor. If you typed students = random.shuffle(students) by accident, students becomes None and the next line crashes — fix it by removing students = .
Recap
3 minrandom.choice answers "pick one". random.shuffle answers "rearrange the whole thing" — in place, returning None. Repeating an item in a list is the simplest way to make it more likely without learning probability formulas. Same engine as the Magic 8-Ball, different verbs and different list — that's a whole genre of game in your back pocket now.
Vocabulary Card
random.shuffle(list)- Rearranges the list in place — the same list comes back in a new order. Returns
None. - in place
- A change made to the original object, not a fresh copy. Common to
shuffle,sort,append,reverse. None- Python's built-in "nothing here" value. What in-place methods return.
- weighted pick
- Making one option more likely by repeating it in the list.
random.choicepicks each item with equal odds — repeating doubles, triples, etc.
Homework
4 minCreate a new file called weekend_planner.py — a tiny "what should we do this weekend?" spinner with weights.
Rules:
import randomat the top.- Build a list called
planswith at least eight different activities, plus three of them repeated to give them a higher chance. For example:"movie at GSC"three times,"hike at Bukit Gasing"twice,"mamak with friends"three times, and several others once each. - Call
random.shuffle(plans)on its own line, then print a header like"The Weekend Lucky Draw". - Use a
while Trueloop. Each turn, ask"Press Enter to spin, or 'done': ". Ondone(case-insensitive),break. Otherwise print"This weekend: <plan>"usingrandom.choice(plans). - Count the spins and print the total at the end.
Bring weekend_planner.py next class — we'll start tackling list challenges without helpers in PY-L1-22.
Sample · weekend_planner.py
# weekend_planner.py — weighted lucky-draw for the weekend import random plans = [ "movie at GSC", "movie at GSC", "movie at GSC", "hike at Bukit Gasing", "hike at Bukit Gasing", "mamak with friends", "mamak with friends", "mamak with friends", "futsal at the community centre", "swim at the public pool", "library marathon", "boardgame afternoon", "cycle around the taman", ] random.shuffle(plans) # in place — own line! print("The Weekend Lucky Draw") print("Press Enter to spin, or type 'done' to finish.") spins = 0 while True: answer = input("\nSpin? ") if answer.lower() == "done": break spins = spins + 1 print("This weekend:", random.choice(plans)) print() print("You spun", spins, "times. Have a great weekend!")
Your activities can be wholly different — eight unique plans is the floor, and at least three of them should be repeated. The non-negotiables: import random, a plans list, random.shuffle(plans) on its own line, a while True loop, a case-insensitive done check with break, random.choice(plans) inside the loop, and a spin counter. If you accidentally wrote plans = random.shuffle(plans), your program will crash on the first spin — remove the plans = bit.