MGU Computer Science Series — Programming with Python
Part V: Files, Data, and Practical Automation
random · datetime · simulation · trials · timedelta
Chapter 24 of 30
24
MGU Computer Science Series  ·  Programming with Python  ·  Library Textbook Edition

Chapter 24:
Dates, Randomness,
and Simulation

Using the random and datetime modules to model uncertainty, work with calendar data, and run programs that observe what usually happens over many trials

■ Part V of VII ■

■ 10 Sections  •  Chapter 24 of 30 ■

Prerequisite: Chapters 1–23 — especially functions, lists, loops, and the standard library

Chapter Introduction and Learning Objectives

Every program you have written so far has produced the same output every time it runs — given the same inputs, the same results appear. But many useful programs need to work differently. A quiz program should shuffle its questions. A game should generate unpredictable outcomes. A scheduling tool should know today's date. A scientific model should run thousands of slightly different trials and report what usually happens.

This chapter introduces two standard-library tools — random and datetime — along with the idea of simulation: using a program to model a situation, run it many times, and observe the results. These tools appear throughout computing, from games and testing to scientific research and probability modeling.

By the end of this chapter you will be able to generate random numbers and make random choices, work with dates and times, build simple simulations, run repeated trials, and interpret what simulation results mean.

Connecting to Earlier Chapters

Chapter 15 gave you a first look at import random and import math. Chapter 21 used import csv. This chapter goes deeper into random and introduces datetime. The loops, functions, lists, and dictionaries from earlier parts of the book all reappear here — randomness and dates become most powerful when you combine them with the structures you already know.

10Sections
9Objectives
17Key Terms
30Total Chapters

Learning Objectives

By the end of this chapter, you should be able to:

  1. 1Use random.randint(), random.random(), and random.uniform() to generate random numbers in a specified range.
  2. 2Use random.choice(), random.shuffle(), and random.sample() to make random selections from sequences.
  3. 3Explain what a seed is and use random.seed() to make random sequences reproducible for testing.
  4. 4Use datetime.date to represent and compare calendar dates.
  5. 5Format dates as readable strings using strftime() and parse date strings using strptime().
  6. 6Calculate durations between dates using subtraction and datetime.timedelta.
  7. 7Design and implement a simulation that runs many trials and accumulates results.
  8. 8Interpret simulation results as estimates of probability, not exact values.
  9. 9Trace programs that use randomness by testing representative cases.

Sections at a Glance

Sections 24.1 – 24.3
Random Numbers and Random Choices
random · randint · random() · uniform · choice · shuffle · sample · seed

Useful Tools from the Standard Library

You have already used the standard library throughout this course. Chapter 15 introduced math and gave you a first look at random. Chapter 21 used the csv module. Chapter 23 used exception types like ValueError and FileNotFoundError. The standard library is a large collection of modules included with every Python installation — you do not need to install anything extra to use them.

This chapter focuses on two modules that are especially useful for practical programs:

  • random — for generating unpredictable values, making selections, and shuffling sequences
  • datetime — for working with dates, times, and durations

Both modules follow the same import pattern you already know.

Python — importing both modules
import random
import datetime

After importing, you call their functions using dot notation: random.randint(...), datetime.date.today(), and so on. This chapter also introduces simulation, which is not a module but a programming technique. A simulation uses a program to model a real-world situation — often one involving randomness — and runs it many times to observe patterns.

Study Note

The random module generates what are technically called pseudo-random numbers — numbers that pass statistical tests for randomness but are actually produced by a deterministic algorithm. For the purposes of this course, they behave as random numbers. For cryptographic applications, Python provides the secrets module, which uses a different approach.

Random Numbers

Random numbers are numbers chosen without a predictable pattern. Python's random module provides several functions for generating them.

random.randint(a, b)

Returns a random integer between a and b, inclusive. Both endpoints can be chosen.

Python — simulating a six-sided die
import random

roll = random.randint(1, 6)
print("You rolled:", roll)

Every time this program runs, roll is one of: 1, 2, 3, 4, 5, or 6. All six values are equally likely.

random.random()

Returns a random float between 0.0 and 1.0, not including 1.0. This is useful when you want a probability value or a percentage.

Python — a random probability value
import random

chance = random.random()
print(chance)   # something like 0.4732891...

random.uniform(a, b)

Returns a random float between a and b. Use this when you need a decimal value in a specific range.

Python — simulated temperature reading
import random

temperature = random.uniform(36.1, 37.2)
print(f"Simulated temperature: {temperature:.1f} degrees")

Tracing programs that use random values

Because random values change every run, tracing a program that uses randomness works differently from tracing one with fixed values. When you trace, choose a representative example value and trace with that — then trace again with a different value near a boundary.

Example 24.2.1
Tracing a program with a random value — two representative cases
  • Programscore = random.randint(0, 100)
    then prints "Pass" if score ≥ 60, else "Fail"
  • Trace A
    score = 73
    73 ≥ 60 is True → prints Pass
  • Trace B
    score = 45
    45 ≥ 60 is False → prints Fail
  • RuleAlways test at least two representative cases — one near each boundary of a condition. For a boundary at 60, test 59, 60, and 61.
LineVariableValue (Trace A)Value (Trace B)Output
3score7345
5score ≥ 60TrueFalse
6 / 8branchif-branchelse-branchPass / Fail

Random Choices

Sometimes you do not want a random number — you want a random item from a list. The random module provides three functions for this, and understanding the differences between them matters.

random.choice(sequence)

Returns one randomly selected item from a sequence. The sequence must not be empty.

Python — picking a random color
import random

colors = ["red", "green", "blue", "yellow"]
picked = random.choice(colors)
print("Chosen color:", picked)

random.shuffle(list)

Randomly rearranges the items of a list in place. The list itself is modified. Nothing is returned.

Python — shuffling a list of questions
import random

questions = ["Q1", "Q2", "Q3", "Q4", "Q5"]
random.shuffle(questions)
print(questions)   # same five items, unpredictable order
Common Mistake — shuffle returns None

random.shuffle() modifies the list directly and returns None. A very common error is assigning the result back to the variable: questions = random.shuffle(questions). This sets questions to None and loses your list. Call random.shuffle(questions) on its own line, without assignment.

random.sample(sequence, k)

Returns a new list of k items chosen from sequence without repetition. The original sequence is unchanged.

Python — selecting 3 random students
import random

students = ["Ana", "Ben", "Cara", "Diego", "Eve", "Finn"]
selected = random.sample(students, 3)
print("Selected:", selected)   # 3 unique names, order varies

Comparing all three functions

random.choice(seq)
Returns
One item
Modifies original?
No
Repeats possible?
N/A (single item)
random.shuffle(lst)
Returns
None
Modifies original?
Yes
Repeats possible?
N/A (rearranges)
random.sample(seq, k)
Returns
New list of k items
Modifies original?
No
Repeats possible?
No — unique items only
Sections 24.4 – 24.5
Simulation and Testing
simulation · trials · proportion · seed · reproducibility

Simulating Repeated Trials

One of the most powerful uses of randomness in programming is running a process many times and observing what usually happens. This is called a simulation. The basic structure of any simulation is:

Python — simulation template
import random

trials = 1000
count_of_interest = 0

for i in range(trials):
    # Simulate one trial
    outcome = ...  # some random result
    if outcome # meets some condition:
        count_of_interest += 1

proportion = count_of_interest / trials
print(f"Proportion: {proportion:.3f}")
Example 24.4.1
Simulating 10,000 coin flips
  • GoalVerify that a fair coin lands heads approximately 50% of the time over many flips.
  • DesignWrite a flip_coin() function that returns "heads" or "tails" with equal probability. Run 10,000 trials. Count heads and compute the proportion.
  • ResultThe proportion should be close to 0.500 but not exactly equal. Randomness produces variation — with more trials the result gets closer to the true probability.
Python — coin flip simulation
import random

def flip_coin():
    return random.choice(["heads", "tails"])

trials = 10000
heads_count = 0

for i in range(trials):
    result = flip_coin()
    if result == "heads":
        heads_count += 1

proportion = heads_count / trials
print(f"Heads in {trials} flips: {heads_count}")
print(f"Proportion: {proportion:.3f}")
Sample output
Heads in 10000 flips: 4987
Proportion: 0.499
Example 24.4.2
Simulating two dice — probability of rolling 7
  • QuestionWhat proportion of rolls with two six-sided dice total exactly 7?
  • Math checkThere are 36 equally likely outcomes. Six of them sum to 7: (1,6), (2,5), (3,4), (4,3), (5,2), (6,1). So the probability is 6/36 ≈ 0.167.
  • SimulationRun 100,000 trials. For each, roll two dice and check if the total is 7.
Python — two-dice simulation
import random

def roll_two_dice():
    die1 = random.randint(1, 6)
    die2 = random.randint(1, 6)
    return die1 + die2

trials = 100000
sevens = 0

for i in range(trials):
    total = roll_two_dice()
    if total == 7:
        sevens += 1

print(f"Sevens: {sevens}")
print(f"Proportion: {sevens / trials:.3f}")
Sample output
Sevens: 16614
Proportion: 0.166

For simple cases like dice, exact probabilities are easy to calculate. But many real situations are complicated enough that simulation is the practical approach: What proportion of customers wait more than 5 minutes? How likely is a student to pass if they guess randomly on a 10-question quiz? How many days does a package typically take to arrive? Simulation answers these questions without advanced mathematics.

Randomness and Testing

Randomness creates a testing challenge: if a program produces different results every time, how do you test it? There are two strategies.

Strategy 1: Test the structure, not the value

Test that the result is in the right range or has the right type — not that it equals a specific value.

Python — testing range, not exact value
import random

result = random.randint(1, 10)
assert 1 <= result <= 10, "Result out of range"

Strategy 2: Use a seed

A seed is a starting value that controls the sequence of random numbers generated. If you set the same seed before running, you get the same sequence every time. This makes randomness predictable for testing purposes.

Python — seeding for reproducible results
import random

random.seed(42)
print(random.randint(1, 6))   # same value every run when seed is 42
print(random.randint(1, 6))
print(random.randint(1, 6))
When to use seeds

Use random.seed(value) when you want to test a random program and need consistent output, when you want someone else to reproduce your simulation results exactly, or when you are debugging a problem that only appears with certain random values. Call random.seed() with no argument — or remove the seed call — when you want genuine unpredictability in the finished program.

Seed Behavior Summary

random.seed(42) — sets the seed to 42; the same sequence of "random" numbers is produced every run. random.seed() — uses the current system time as the seed; different every run. No seed call — same as calling random.seed(); different every run.

Sections 24.6 – 24.8
Working with Dates and Times
datetime.date · strftime · strptime · timedelta · durations

Dates and Times

Many useful programs need to work with dates and times: What day is today? How many days until a deadline? How long has it been since a file was created? What day of the week does a birthday fall on? Python's datetime module handles all of these.

The module provides several types. The two most useful for beginners are datetime.date (a calendar date: year, month, day) and datetime.datetime (a date and a time together). This chapter focuses on datetime.date.

Getting today's date

Python — today's date
import datetime

today = datetime.date.today()
print(today)
Sample output (date when code runs)
2025-03-14

Dates display in YYYY-MM-DD format by default. Section 24.7 shows how to change this.

Creating a specific date

Python — constructing a specific date
import datetime

birthday = datetime.date(2007, 9, 22)   # arguments: (year, month, day)
print(birthday)   # 2007-09-22

Reading parts of a date

Python — accessing year, month, day
import datetime

today = datetime.date.today()
print("Year:",  today.year)
print("Month:", today.month)
print("Day:",   today.day)
Sample output
Year: 2025
Month: 3
Day: 14

Formatting Dates

The default date format (YYYY-MM-DD) is machine-readable but not always what you want to show a user. The strftime() method converts a date into a formatted string. Its name stands for "string format time."

Using strftime()

Python — formatting a date as readable text
import datetime

today = datetime.date.today()
formatted = today.strftime("%B %d, %Y")
print(formatted)
Sample output
March 14, 2025

Common format codes

CodeMeaningExample output
%YFour-digit year2025
%yTwo-digit year25
%mMonth as number (01–12)03
%BFull month nameMarch
%bAbbreviated month nameMar
%dDay of month (01–31)14
%AFull weekday nameFriday
%aAbbreviated weekday nameFri
Python — several format examples for the same date
import datetime

d = datetime.date(2025, 9, 22)
print(d.strftime("%A, %B %d, %Y"))   # Monday, September 22, 2025
print(d.strftime("%m/%d/%Y"))          # 09/22/2025
print(d.strftime("%d %b %Y"))           # 22 Sep 2025

Parsing a date string with strptime()

Sometimes you receive a date as a string — from user input, a file, or a CSV — and need to convert it to a date object. datetime.datetime.strptime() does this. The second argument must match the format of the string exactly.

Python — parsing a date string
import datetime

date_string = "2025-09-22"
parsed = datetime.datetime.strptime(date_string, "%Y-%m-%d").date()
print(parsed)         # 2025-09-22
print(parsed.year)    # 2025
strftime vs. strptime — the direction matters

strftime() — takes a date object and converts it to a formatted string (date → string). strptime() — takes a date string and converts it back to a datetime object (string → date). The "f" stands for format (output); the "p" stands for parse (input).

Simple Timers and Durations

Date arithmetic with timedelta

The difference between two dates is called a duration. Python represents this with datetime.timedelta. Subtracting two date objects produces a timedelta. Its .days attribute gives the number of days in the duration.

Python — days until a future date
import datetime

today     = datetime.date.today()
new_year  = datetime.date(2026, 1, 1)
days_away = new_year - today
print(f"Days until New Year: {days_away.days}")

Adding or subtracting time

You can add a timedelta to a date to find a future or past date.

Python — adding and subtracting timedelta
import datetime

today      = datetime.date.today()
one_week   = datetime.timedelta(days=7)
next_week  = today + one_week
print("Today:",           today)
print("One week from now:", next_week)

# Also works for deadlines
deadline      = datetime.date(2025, 12, 31)
buffer        = datetime.timedelta(days=14)
reminder_date = deadline - buffer
print("Set reminder for:", reminder_date)

Days between two dates

Python — semester length in days
import datetime

start    = datetime.date(2025, 9, 1)
end      = datetime.date(2025, 12, 20)
duration = end - start
print(f"Semester length: {duration.days} days")

Timing program execution

Python — measuring elapsed time
import datetime

start_time = datetime.datetime.now()

# some code that takes time
total = 0
for i in range(10_000_000):
    total += i

end_time = datetime.datetime.now()
elapsed  = end_time - start_time
print(f"Time elapsed: {elapsed}")
Precision timing

For precise measurement of short code segments, the standard library also provides time.perf_counter(), which is more accurate than datetime.datetime.now() for very short durations. For the exercises in this chapter, datetime is clear and readable.

Sections 24.9 – 24.10
Building and Interpreting Simulations
simulation design · distribution · expected value · garbage in, garbage out

Building Simple Simulations

Every simulation follows a similar four-step structure:

  • Set up parameters — how many trials, what rules apply
  • Run each trial using randomness
  • Collect results from each trial
  • Summarize or display the results
Example 24.9.1
Quiz guessing simulation — what score does random guessing produce?
  • SetupA 10-question multiple-choice quiz has 4 choices per question. A student guesses randomly on every question.
  • ExpectedThe expected score is 10 × (1/4) = 2.5 correct answers.
  • VerifyRun 10,000 simulated quizzes and check the average.
Python — quiz guessing simulation
import random

def simulate_quiz(num_questions, num_choices):
    """Simulate a student guessing randomly on every question."""
    correct = 0
    for q in range(num_questions):
        guess  = random.randint(1, num_choices)
        answer = 1   # correct answer is always choice 1
        if guess == answer:
            correct += 1
    return correct

trials        = 10000
total_correct = 0

for t in range(trials):
    total_correct += simulate_quiz(10, 4)

average = total_correct / trials
print(f"Average score from random guessing: {average:.2f} out of 10")
print(f"Expected: 2.50 out of 10")
Sample output
Average score from random guessing: 2.51 out of 10
Expected: 2.50 out of 10

Collecting a distribution

Instead of averaging, you can collect how often each score appears — a distribution. Use a dictionary where the keys are scores and the values are counts.

Python — collecting score distribution
import random

def simulate_quiz(num_questions, num_choices):
    correct = 0
    for q in range(num_questions):
        if random.randint(1, num_choices) == 1:
            correct += 1
    return correct

trials       = 10000
score_counts = {}

for t in range(trials):
    score = simulate_quiz(10, 4)
    if score not in score_counts:
        score_counts[score] = 0
    score_counts[score] += 1

print("Score | Count | Proportion")
print("------+-------+-----------")
for score in sorted(score_counts):
    count      = score_counts[score]
    proportion = count / trials
    print(f"  {score:2d}  | {count:5d} | {proportion:.3f}")
Sample output
Score | Count | Proportion
------+-------+-----------
   0  |   563 | 0.056
   1  |  1878 | 0.188
   2  |  2814 | 0.281
   3  |  2499 | 0.250
   4  |  1460 | 0.146
   5  |   561 | 0.056
   6  |   173 | 0.017
   7  |    43 | 0.004
   8  |     8 | 0.001
   9  |     1 | 0.000
  10  |     0 | 0.000

Most random guesses score 1, 2, or 3. Very few score above 5. This matches what we would expect from probability — the distribution reveals a pattern that a single average cannot.

Interpreting Simulation Results

Running a simulation produces numbers. Interpreting those numbers correctly requires care. Here are the key principles.

Principle 1
Results are approximate
Simulation results have variation — running the same simulation twice gives slightly different numbers unless you use a seed. For simple simulations, use at least 10,000 trials. For more precise estimates, use 100,000 or more.
Principle 2
Proportion estimates probability
A proportion from a simulation is an estimate of a probability, not the probability itself. If your simulation shows 16.7% of two-dice rolls total 7, the actual probability is 6/36 = 16.67%. The simulation is close — not exact.
Principle 3
Averages are expected values
An average from a simulation is the expected value — the typical result over many trials. It does not describe any single trial. A student guessing randomly might score 0 or 5 on one quiz, but averages about 2.5 over many quizzes.
Principle 4
Garbage in, garbage out
A simulation is only as good as its model. If you model a biased coin as a fair one, your results will be wrong regardless of trial count. Always ask: does this simulation accurately represent the situation being modeled?

When simulation is most useful

Simulation is useful when…Simulation is less useful when…
The exact probability requires complicated mathematics The exact answer is easy to calculate directly
You want to model how a system behaves under different conditions The model does not accurately represent the real situation
You want to test assumptions about randomness or fairness The number of trials is too small to give reliable estimates
You are designing a game and want to check balance The program runs too slowly to complete enough trials

Chapter Summary

Key Terms

random module
A standard library module providing functions for generating random numbers, making random selections, and shuffling sequences.
random.randint(a, b)
Returns a random integer from a to b, inclusive. Both endpoints can be chosen.
random.random()
Returns a random float between 0.0 and 1.0, not including 1.0.
random.uniform(a, b)
Returns a random float between a and b.
random.choice(sequence)
Returns one randomly selected item from a non-empty sequence.
random.shuffle(list)
Randomly rearranges the items of a list in place. Returns None — do not assign the result.
random.sample(sequence, k)
Returns a new list of k unique items chosen from the sequence without modifying the original.
seed
A starting value passed to random.seed() that makes a sequence of random numbers reproducible. The same seed always produces the same sequence.
datetime module
A standard library module for working with calendar dates, times, and durations.
datetime.date
A type representing a calendar date as (year, month, day). Supports comparison, subtraction, and arithmetic with timedelta.
strftime(format)
Converts a date object to a formatted string using codes like %Y (year), %B (month name), %d (day), %A (weekday).
strptime(string, format)
Parses a date string and returns a datetime object. The format argument must match the string's structure exactly.
timedelta
Represents a duration — the difference between two dates. Its .days attribute gives the number of days in the duration.
simulation
A program that models a random or uncertain process by running many trials and observing the results.
trial
One run of a simulated process.
proportion
The fraction of trials that produced a particular outcome. An estimate of the true probability of that outcome.
expected value
The average result over many trials of a random process. Does not describe any single trial — describes typical behavior across many.
Code ReadingRead and Explain

Read each block carefully. Answer the questions without running the code.

Exercise 24-R1
Python
import random

total = 0
for i in range(5):
    total += random.randint(1, 10)

print(total)
  1. What is the minimum possible value of total?
  2. What is the maximum possible value of total?
  3. Is there a single correct answer for what this program prints? Explain.
Exercise 24-R2
Python
import random

items = ["apple", "banana", "cherry", "date"]
random.shuffle(items)
print(items[0])
  1. What are the four possible outputs?
  2. Could this program ever print "elderberry"? Explain.
  3. If you ran this program 1,000 times, roughly how often would you expect it to print "apple"?
Exercise 24-R3
Python
import datetime

start = datetime.date(2025, 1, 15)
end   = datetime.date(2025, 3, 15)
gap   = end - start
print(gap.days)
  1. Without running it, calculate what this prints. (Count days in January and February 2025.)
  2. What type is gap?
  3. What would happen if you printed gap instead of gap.days?
Exercise 24-R4
Python
import random

random.seed(99)
values = [random.randint(1, 100) for i in range(4)]
print(values)

random.seed(99)
values2 = [random.randint(1, 100) for i in range(4)]
print(values2)
  1. Will values and values2 be equal? Explain why.
  2. What does resetting the seed accomplish?
  3. If you removed both random.seed(99) lines, would values and values2 still be equal? Explain.
Code TracingTrace Program Execution
Exercise 24-T1

Trace this program. Assume random.randint(1, 6) returns 2 on the first call and 5 on the second call.

Python
import random

def roll():
    return random.randint(1, 6)

total = roll() + roll()
if total >= 7:
    print("High roll:", total)
else:
    print("Low roll:", total)
StepExpression evaluatedValueOutput
1first call to roll()2
2second call to roll()5
3total?
4total >= 7?
5branch taken??
Exercise 24-T2

Trace this simulation loop for 5 trials. Assume random.randint(1, 4) returns, in order: 3, 1, 4, 1, 2.

Python
import random

correct = 0
for trial in range(5):
    guess = random.randint(1, 4)
    if guess == 1:
        correct += 1

print(correct)
Trialguessguess == 1correct after
0
1
2
3
4

What does the program print?

Exercise 24-T3

Trace this date program step by step.

Python
import datetime

event     = datetime.date(2025, 6, 30)
today     = datetime.date(2025, 6, 10)
days_away = event - today

if days_away.days <= 7:
    print("Coming up soon!")
elif days_away.days <= 30:
    print("This month")
else:
    print("Further out")
StepExpressionValue
1event
2today
3days_away
4days_away.days
5days_away.days <= 7
6days_away.days <= 30
7output
Predict the OutputWhat does this print?

Where output depends on randomness, state the possible range or list of possible outputs.

Exercise 24-P1
Python
import datetime

d = datetime.date(2025, 11, 28)
print(d.strftime("%A, %B %d"))

Hint: November 28, 2025 is a Friday. What does this print exactly?

Exercise 24-P2
Python
import random

random.seed(7)
choices = random.sample([10, 20, 30, 40, 50], 3)
print(len(choices))
print(type(choices))

What can you say for certain about the output, regardless of what the seed produces?

Exercise 24-P3
Python
import datetime

today     = datetime.date(2025, 3, 1)
delta     = datetime.timedelta(days=365)
next_year = today + delta
print(next_year)

What does this print? (Think carefully about whether 2025 or 2026 is a leap year.)

Exercise 24-P4
Python
import random

items = ["red", "blue"]
for i in range(3):
    print(random.choice(items))

List all possible outputs. There are 2³ = 8 possible combinations. Write them out.

DebuggingFind and Fix the Error

Each program below contains an error. Identify the error, explain what it causes, and write the corrected version.

Exercise 24-D1
Python — contains an error
import random

cards = ["A", "2", "3", "4", "5", "J", "Q", "K"]
cards = random.shuffle(cards)
print(cards[0])

What error does this cause, and on which line? Explain why, then write the correct version.

Exercise 24-D2
Python — contains an error
import datetime

birthday = datetime.date(1998, 13, 5)
print(birthday)

What error does this cause? What is the argument that causes the problem?

Exercise 24-D3
Python — logic error
import random

total = 0
for i in range(10):
    total = random.randint(1, 6)

print("Total:", total)

This runs without error but produces wrong results. What is the logic error? What should the assignment on line 5 look like?

Exercise 24-D4
Python — surprising but valid
import datetime

date1 = datetime.date(2025, 5, 1)
date2 = datetime.date(2025, 8, 15)
gap   = date1 - date2
print("Days:", gap.days)

This runs without error. What does it print? Is the result a negative number? Is that meaningful? When would you want a negative timedelta?

Exercise 24-D5
Python — contains an error
import random

random.seed(42)
result = random.choice([])
print(result)

What error does this cause, and why? What rule does this illustrate about random.choice()?

Short TasksShort Programming Tasks

Write clean, readable code with clear variable names.

  1. Random password component. Write a program that uses random.choice() and a string of characters to generate a random 8-character password component. Include at least letters and digits in your character set. Print the result. Hint: build the result by iterating 8 times and appending each random character to a growing string.
  2. Birthday countdown. Ask the user to enter an upcoming birthday in the format YYYY-MM-DD. Parse it into a datetime.date object. Calculate how many days until that birthday and print a message. Handle the case where the entered date is in the past with a clear message.
  3. Shuffle and deal. Create a list representing a simplified deck using labels like "2H", "KS", "AS" for 13 cards in one suit, or simply numbers 1–52. Shuffle the deck and print the first 5 cards as a hand.
  4. Day of the week finder. Ask the user to enter a date in the format MM/DD/YYYY. Convert it to a datetime.date object and print which day of the week that date falls on.
  5. Random sample quiz selector. Create a list of at least 10 quiz questions as strings. Use random.sample() to select 5 questions. Print the selected 5, numbered 1 through 5.
  6. Biased coin simulation. A biased coin lands heads 70% of the time and tails 30%. Simulate 10,000 flips and report the proportion of heads and tails. Hint: use random.random() and check if the result is less than 0.70.
Mini-ProjectFlashcard or Quiz Simulator
Project Description
Build a complete flashcard session program combining randomness and date tracking
  • Requirement 1Store at least 8 flashcard pairs (question and answer) as a list of dictionaries.
  • Requirement 2Shuffle the flashcards at the start of each session using random.shuffle().
  • Requirement 3Present each flashcard: show the question, wait for input, then reveal the answer.
  • Requirement 4Ask the user to rate each card as correct or wrong (y/n). Track the count of correct answers.
  • Requirement 5At the end of the session, print a summary: date of session (formatted with strftime()), total cards, correct count, and percentage correct.

Example session

Example interaction
=== Flashcard Session ===
Date: March 14, 2025

Card 1 of 8
Question: What keyword defines a function in Python?
Your answer: def
Answer: def
Correct? (y/n): y

Card 2 of 8
Question: What does len() return for an empty list?
Your answer: 0
Answer: 0
Correct? (y/n): y

...

=== Session Summary ===
Date: March 14, 2025
Cards studied: 8
Correct: 6
Score: 75.0%

Optional extensions

  1. Save the session result (date, score, total) to a text file and load it at the start to show the student's history across multiple sessions.
  2. Repeat missed cards at the end of the session before showing the final summary.
  3. Let the user choose how many cards to study using random.sample() instead of always showing all cards.

Planning guide

Before writing any code, answer these questions in comments at the top of your file: (1) What data structure will hold the flashcards? (2) How will you shuffle them? (3) What variables do you need during the session? (4) How will you calculate the final percentage? (5) What format will you use to display the date?

Mixed ReviewCombining Earlier Skills
  1. pick_winner and run_giveaway. Write a function called pick_winner(names) that takes a list of names and returns one randomly selected name. Write a second function called run_giveaway(names, num_winners) that uses random.sample() to select multiple unique winners. Test both functions with a list of at least 6 names.
  2. Sort dates from a file. Write a program that reads a list of dates from a text file (one date per line in YYYY-MM-DD format), converts each to a datetime.date object, and prints the dates in chronological order from earliest to latest. Hint: datetime.date objects support comparison operators like < and >, so you can sort a list of them.
  3. simulate_guessing function. Write a function simulate_guessing(num_questions, num_choices, trials) that simulates a student guessing randomly on a quiz for the given number of trials and returns the average score as a float. Test it with several different values of num_questions and num_choices and print the results in a table.
  4. Random date generator. Write a program that generates a random date within a given year and prints it in a readable format. Ask the user for the year. Use random.randint() to pick a month (1–12) and a day. To keep it simple, allow only days 1–28 (valid for every month), or handle different month lengths for a greater challenge.
ReviewReview Questions

Recall and Vocabulary

  1. What is the difference between random.choice() and random.sample()?
  2. Why does random.shuffle() return None instead of the shuffled list?
  3. What is a seed, and why would you use one?
  4. What does datetime.date.today() return? What type is the result?
  5. What is the difference between strftime() and strptime()?
  6. If you subtract two datetime.date objects, what type is the result? How do you get the number of days from it?
  7. What does it mean for a simulation result to be approximate? Why does increasing the number of trials improve accuracy?

Understanding and Explanation

  1. Describe a situation where simulation would give you useful information that simple arithmetic could not easily provide. Explain why simulation is the better approach in that situation.
  2. A student writes this code to shuffle a list and pick the first item:
    Python — contains an error
    cards = ["A", "B", "C", "D"]
    picked = random.shuffle(cards)
    print(picked[0])
    What error will occur? What is the correct way to write this?
  3. You run a simulation 100 times and find that an event occurs 23 times. You run the same simulation again and find it occurs 31 times. Is this a sign that something is wrong? Explain.
  4. What does "garbage in, garbage out" mean in the context of simulation? Give a concrete example.

Application and Design

  1. A board game uses three six-sided dice and rewards players who roll triples (all three dice show the same number). Design a simulation to estimate the probability of rolling triples. Write out the structure in pseudocode before writing Python. How many trials would you use, and why?
  2. You want to test a function called deal_card(deck) that removes and returns a random card from a list. What would you test using assert statements? List at least three things you could check without knowing the exact card drawn.
  3. A teacher wants a program that randomly assigns 24 students to 6 groups of 4. Describe which random function you would use and why. Write the key line of Python that performs the selection. What happens if the class has 25 students?
Chapter 24 Checklist
Confirm your understanding before moving to Chapter 25
Random Numbers
  • I can use random.randint(a, b) to generate a random integer in a range.
  • I can use random.random() for a random float in [0.0, 1.0).
  • I can use random.uniform(a, b) for a random float in any range.
Random Choices
  • I can use random.choice() to pick one item from a sequence.
  • I understand that random.shuffle() modifies in place and returns None.
  • I can use random.sample() to select multiple unique items without modifying the original.
Seeds and Testing
  • I can explain what a seed is and why it makes a program reproducible.
  • I can test a random program by checking range or type instead of exact value.
  • I know when to use a seed and when to remove it.
Dates
  • I can get today's date with datetime.date.today() and create specific dates.
  • I can format a date as a readable string using strftime() with common codes.
  • I can parse a date string using strptime().
  • I can calculate the number of days between two dates using subtraction and .days.
Simulation
  • I can design a simulation using the four-step pattern: parameters, trials, collect, summarize.
  • I understand that simulation results are approximations that improve with more trials.
  • I can distinguish proportion (an estimate) from exact probability.
  • I can explain what "garbage in, garbage out" means for simulation.
Preview — Chapter 25
Automating Everyday Tasks

Chapter 24 introduced randomness, dates, and simulation — tools for modeling uncertainty and working with calendar data. Chapter 25 takes a different direction and asks: how can Python automate practical, repetitive work? You will learn to write programs that process many files, generate reports, handle command-line arguments, use configuration values, and perform repetitive tasks efficiently. The random module from this chapter and the file-handling skills from Chapters 21–22 both reappear in the automation context. As always, the focus is on writing automation that is safe, reversible, and well-tested before being run on real data.

MGU Library Connection
  • Programming with Python — Appendix J: Standard Library Beginner Map (random, datetime)
  • Programming with Python — Appendix L: Testing and Refactoring Reference
  • Companion resource: Standard Library Beginner Chart
  • Companion resource: Debugging Checklist
  • Prerequisite: Chapter 15 (Modules, Imports, and Standard Library Basics)
  • Next course: Python for Data Science (simulation and probability used extensively)