Python 30‑by‑30 Course
You've got the basics down! This week, we'll level up by learning how to make our programs repeat tasks, handle errors without crashing, and start thinking like a problem-solver.
In Module 1, we built our foundation. Here's what we covered:
>>>
) and run .py
scripts.print()
and input()
to communicate with the user.int
, float
), text (str
), and booleans (True
/False
).if
, elif
, and else
.[]
, tuples ()
, dictionaries {}
, and sets {}
.if
/elif
/else
skills.You've already learned how to use if
to make your code choose a path. Now, let's make those decisions more powerful. Often, you'll need to check multiple things at once. You can do this by combining conditions with and
(both must be true) or or
(at least one must be true). For example, you might give a discount if a customer is a member or if it's their birthday.
Python also lets you write more natural-looking comparisons. Instead of writing score >= 80 and score < 90
, you can simply write 80 <= score < 90
. It reads just like it does in maths! There's also a handy shortcut for simple if/else
choices, sometimes called a "ternary operator." You can write result = 'Pass' if score >= 50 else 'Fail'
, which is a neat, one-line way to assign a value based on a condition.
As you build more complex programs, like figuring out shipping costs based on weight and destination, you'll find yourself "nesting" these conditions. This just means putting an if
statement inside another if
statement. Just be careful—if you nest too deeply, your code can become hard to read. Sometimes it's better to reorganize your logic or use a different tool, like a dictionary, to map situations to outcomes.
Write a program to calculate shipping costs. Ask the user for the package weight and if they want express shipping. Rules: Standard shipping is $5. If the package is over 10kg, add $10. If express shipping is chosen, add $15. The user should only be charged one fee for weight, but express is an additional cost.
# shipping_cost_calculator.py
weight = float(input("Enter package weight in kg: "))
express = input("Express shipping? (yes/no): ").lower()
cost = 5.00 # Base cost
if weight > 10:
cost += 10.00
if express == 'yes':
cost += 15.00
print(f"The total shipping cost is: ${cost:.2f}")
for
and while
.range()
to loop a specific number of times.break
and continue
.Loops are one of the biggest superpowers in programming. They let you automate repetitive tasks. Python has two main kinds. The first is the for
loop, which you use when you want to go through a sequence of items, like a list or a string. For each item, the loop runs your block of code. To loop a set number of times, the range()
function is your best friend. For example, for i in range(5):
will run the code inside it exactly five times (with `i` being 0, 1, 2, 3, and then 4).
The second type is the while
loop. This loop keeps running *as long as* a certain condition is True
. It's perfect for situations where you don't know in advance how many times you'll need to repeat something, like in a menu where you keep asking for user input until they choose to 'quit'.
Sometimes you need to change a loop's behavior mid-stream. For that, you have two key commands. The break
statement is your emergency exit; it stops the loop immediately, no matter what. The continue
statement is like a 'skip' button; it immediately jumps to the next iteration of the loop, skipping any code that came after it for the current item.
Write a simple number guessing game. The computer should pick a secret number between 1 and 100. The user gets to guess. Use a `while` loop that continues until the user guesses correctly. After each guess, tell them if they were "Too high!" or "Too low!".
# guessing_game.py
import random
secret_number = random.randint(1, 100)
guess = None
print("I'm thinking of a number between 1 and 100.")
while guess != secret_number:
try:
guess = int(input("What's your guess? "))
if guess < secret_number:
print("Too low!")
elif guess > secret_number:
print("Too high!")
except ValueError:
print("Please enter an actual number.")
print(f"You got it! The number was {secret_number}. 🎉")
try
and except
.raise
.Real-world programs have to deal with the unexpected. What if a user types "ten" instead of "10"? Or tries to open a file that doesn't exist? Right now, that would crash your program. Today, we learn how to make our code more robust by handling exceptions.
The main tool for this is the try...except
block. You put your "risky" code inside the `try` block. If everything runs fine, the `except` block is ignored. But if an error (an exception) occurs, instead of crashing, Python immediately jumps to the `except` block and runs that code instead. This gives you a chance to print a helpful message, ask the user for input again, or just move on gracefully.
A common pattern is to wrap a `try...except` block inside a `while` loop. This allows you to keep asking the user for input until they give you something valid. You can also signal your own errors. If a function gets an argument that doesn't make sense (like a negative number for an age), you can use the raise
keyword to create your own exception. This makes your code's rules clear and helps you find bugs faster.
Create a simple calculator that asks for two numbers and an operator (+, -, *, /). Wrap the logic in a `try...except` block. You should handle two main errors: the user entering non-numeric input (ValueError
) and the user trying to divide by zero (ZeroDivisionError
).
# safe_calculator.py
try:
num1 = float(input("Enter first number: "))
op = input("Enter operator (+, -, *, /): ")
num2 = float(input("Enter second number: "))
if op == '+':
result = num1 + num2
elif op == '-':
result = num1 - num2
elif op == '*':
result = num1 * num2
elif op == '/':
result = num1 / num2
else:
result = "Invalid operator"
print(f"The result is: {result}")
except ValueError:
print("Error: Please enter valid numbers.")
except ZeroDivisionError:
print("Error: You cannot divide by zero!")
The word "algorithm" sounds intimidating, but it's just a fancy name for a step-by-step recipe to solve a problem. You use algorithms all the time, like when you follow instructions to assemble furniture or a recipe to bake a cake. In programming, it's about breaking down a large task into small, manageable steps that the computer can follow.
A great way to practice this is to write out your plan in plain English first. This is called pseudocode. Before you write a single line of Python, you might jot down notes like "1. Go through each item in the list. 2. Check if the item is what I'm looking for. 3. If it is, stop and report the position." This clarifies your thinking and makes writing the actual code much easier.
Today, we'll try this by building a simple search function. Of course, Python has built-in ways to do this that are much faster (like `list.index()`), but building it yourself is a fantastic way to understand the logic that powers those tools. Thinking algorithmically is one of the most fundamental skills in programming. It's how you go from knowing the syntax to actually solving real-world problems.
Write a function called `find_max` that takes a list of numbers and returns the largest number in the list. Do it without using the built-in `max()` function. Your "recipe" should be: create a variable to hold the max value, loop through the list, and if you find a number bigger than your current max, update it.
# find_max_algorithm.py
def find_max(numbers):
# Handle the edge case of an empty list
if not numbers:
return None
# Step 1: Assume the first number is the biggest to start
max_so_far = numbers[0]
# Step 2: Loop through the rest of the numbers
for number in numbers:
# Step 3: If we find a bigger one, update our max
if number > max_so_far:
max_so_far = number
# Step 4: Return the biggest one we found
return max_so_far
# --- Test it out ---
my_scores = [78, 92, 45, 100, 88]
print(f"The highest score is: {find_max(my_scores)}") # Expected: 100
empty_list = []
print(f"The max of an empty list is: {find_max(empty_list)}") # Expected: None
Today we tackle a challenge that has become a classic first test for programmers: FizzBuzz. It's a simple puzzle that beautifully combines everything you've learned so far: loops, `if/elif/else` conditions, and the modulus operator (%
) for checking divisibility.
Here's the task: Write a program that prints the numbers from 1 to 100. But, there's a catch:
The trickiest part is handling the numbers that are multiples of both 3 and 5 (like 15, 30, etc.). Think about the order of your `if/elif` checks. If you check for "divisible by 3" first, you'll print "Fizz" for the number 15 and never get to the "FizzBuzz" part. This puzzle teaches you to think carefully about the order of your logic. Solving it is a small but satisfying milestone!
First, write your own solution to the FizzBuzz problem from 1 to 100. After you get it working, try to create a function that takes three arguments: a limit, a number for "Fizz", and a number for "Buzz", so you could run `custom_fizzbuzz(50, 4, 7)` if you wanted to!
# fizzbuzz_solution.py
# The classic FizzBuzz
print("--- Classic FizzBuzz ---")
for num in range(1, 101):
# Check for the most specific case FIRST
if num % 3 == 0 and num % 5 == 0:
print("FizzBuzz")
elif num % 3 == 0:
print("Fizz")
elif num % 5 == 0:
print("Buzz")
else:
print(num)
# A more advanced, flexible version
def custom_fizzbuzz(limit, fizz_num, buzz_num):
print(f"\n--- Custom FizzBuzz up to {limit} ---")
for num in range(1, limit + 1):
output = ""
if num % fizz_num == 0:
output += "Fizz"
if num % buzz_num == 0:
output += "Buzz"
if not output:
print(num)
else:
print(output)
custom_fizzbuzz(30, 2, 7) # Fizz for evens, Buzz for mult of 7