Adrian Dane

Python 30‑by‑30 Course

Module 3: Functions, Modules, and Data Structures

It's time to get organized! In this module, you'll learn how to bundle your code into reusable tools called functions, import code from other files, and handle more complex, nested data. This is how we go from writing simple scripts to building structured programs.

Contents

Quick Recap of Module 2

In Module 2, we learned how to control the flow of our programs:

  • Advanced Conditions: We combined conditions with and/or and learned about nesting if statements.
  • Loops: We mastered the two loop types: for loops for iterating over sequences (like a list or range()) and while loops for repeating code as long as a condition is true.
  • Error Handling: We made our code crash-proof by using try...except blocks to catch potential errors like ValueError and ZeroDivisionError.
  • Algorithms: We practiced breaking down problems into step-by-step "recipes" (pseudocode) and solved the classic FizzBuzz challenge.

Day 11: Creating Your Own Tools (Functions)

Objectives

Have you ever found yourself writing the same few lines of code over and over? That's a sign you need a function! A function is a named block of reusable code that performs a specific task. You define it once using the def keyword, and then you can "call" it by name as many times as you want. This is a core principle of programming: Don't Repeat Yourself (DRY).

Functions can take inputs, called parameters (or arguments), which are variables they use to do their work. For example, a greet(name) function would take a name as a parameter. They can also give back a result using the return statement. Good functions are like specialized tools: they do one thing and do it well. For example, you might write a function to calculate the area of a circle, or another to validate a user's email address.

It's also great practice to write a short explanation of what your function does right below its definition. This is called a docstring, and you create it with triple quotes """...""". It helps other people (and your future self!) understand your code without having to read every line.

🤯 What's the big deal with functions? A Coffee Analogy.

A function is like a coffee machine. ☕

  • It has a specific job: To make coffee. You don't use it to toast bread.
  • It takes inputs (parameters): You have to give it water and coffee grounds.
  • You "call" it: You press the 'start' button.
  • It gives something back (a return value): It gives you a delicious cup of coffee.

You can use the machine over and over without needing to know the complex details of how it heats the water or grinds the beans. Functions let you do the same with your code: use a simple command to perform a complex task.

Practice ✍️

Write a function named celsius_to_fahrenheit that takes one number (a temperature in Celsius) as a parameter and returns the equivalent temperature in Fahrenheit. The formula is $(C \times 9/5) + 32$. Test it with a few values like 0, 20, and 100.

Click to view sample functions
# temperature_converter.py
def celsius_to_fahrenheit(celsius_temp):
    """Converts a temperature from Celsius to Fahrenheit."""
    fahrenheit = (celsius_temp * 9/5) + 32
    return fahrenheit

# --- Let's test it ---
temp1 = 0
temp2 = 20
print(f"{temp1}°C is {celsius_to_fahrenheit(temp1)}°F")
print(f"{temp2}°C is {celsius_to_fahrenheit(temp2)}°F")
          

Day 12: Organizing Your Code with Toolboxes (Modules)

Objectives

As you write more functions, your script file can get long and messy. The solution is to organize your code into separate files called modules. A module is simply a Python file (with a .py extension) containing functions, classes, or variables that you can import into other scripts. This keeps your code clean and reusable across different projects.

Python comes with a huge standard library of pre-made modules that you can use right away. Need to work with dates? import datetime. Need random numbers? import random. These are powerful tools you don't have to build from scratch. You can create your own modules just as easily. If you save a file named my_tools.py, you can use import my_tools in another file to access all its functions.

But the real power comes from the global Python community. There's a giant online repository of code called the Python Package Index (PyPI). You can use a command-line tool called pip to install these "third-party packages." For example, running pip install requests gives you a powerful module for interacting with websites, saving you hundreds of hours of work.

🤯 Modules? Packages? What's the difference?

Think of it like organizing your workshop. 🧰

  • A single function is a tool, like a screwdriver.
  • A module (.py file) is a toolbox. You put related tools (functions) in it. For example, a geometry.py toolbox holds your calculate_area and calculate_perimeter tools.
  • The Python Standard Library is the set of toolboxes that came with your house. You already have toolboxes for `math`, `random`, and `datetime` ready to go.
  • PyPI is a giant online hardware store, and pip is your delivery service. You can order any specialized toolbox you can imagine (pip install ...), and it gets delivered right to your workshop.

Practice ✍️

Create a module named string_utils.py. Inside it, define a function reverse_string(s) that returns a reversed version of a string. In a separate main script, import your new module and use it to reverse a string that the user provides.

Click to view sample modules and scripts
# string_utils.py (this is one file)
def reverse_string(s):
    """Returns the reversed version of a string s."""
    return s[::-1] # A cool Python slicing trick!

# ------------------------------------------------
# main_script.py (this is a separate file in the same folder)
import string_utils

user_text = input("Enter some text to reverse: ")
reversed_text = string_utils.reverse_string(user_text)
print(f"Here it is reversed: {reversed_text}")
        

Are you finding this course useful?

Hundreds of hours of research and development have gone into creating this free course. If you're enjoying the lessons, please consider a small token of appreciation as thanks.

Your support helps cover ongoing server costs and, more importantly, fuels the creation of more free, high-quality learning materials for everyone. Thank you!

Buy Me a Coffee ☕

Day 13: Data Inception (Nested Data & Recursion)

Objectives

So far, our lists and dictionaries have been simple. But in the real world, data is often nested. You might have a list of lists to represent a tic-tac-toe board, or a dictionary where a value is another dictionary, like a user profile with a nested dictionary for 'address'. This is incredibly common when you get data from websites (in a format called JSON).

Working with this kind of data can be tricky. How do you find something buried deep inside? One powerful, though sometimes mind-bending, technique is recursion. A recursive function is a function that calls itself to solve a smaller piece of the same problem. Think of it as breaking a big problem down into identical, smaller sub-problems until you reach a simple one you can solve directly.

Every recursive function needs two things: 1) a base case—a condition that tells the function when to stop calling itself—and 2) a recursive step, where it calls itself with a slightly simpler version of the problem. It's perfect for navigating hierarchical data, like a file system where you need to process every file in every sub-folder.

🤯 Recursion makes my head spin. Is there a simple way to think about it?

Recursion is like Russian Nesting Dolls. 🪆

Imagine you want to count how many dolls are in a set. What's your process?

  1. You open the big, outer doll.
  2. Inside, you find... another, slightly smaller nesting doll.
  3. What do you do with this new doll? You apply the exact same process to it: you open it. (This is the function "calling itself" on a smaller version of the problem).
  4. You keep repeating this until you find the tiny, solid doll that can't be opened. This is your base case—the point where you stop.

Recursion solves a problem by saying, "The solution to this big problem is to do a small action and then apply the exact same solution to the smaller thing I found inside."

Practice ✍️

Write a recursive function countdown(n) that prints numbers from `n` down to 1. The base case is when `n` is 0, at which point the function should just stop. The recursive step should print the current `n` and then call countdown(n-1).

Click to view sample recursive functions
# recursive_countdown.py
def countdown(n):
    # Base Case: If n is 0 or less, we stop.
    if n <= 0:
        print("Blast off! 🚀")
        return # This ends the function call

    # Recursive Step: Print the number, then call itself with a smaller number.
    print(n)
    countdown(n - 1)

# --- Let's try it ---
countdown(5)
        

Day 14: Python's Super-Shortcuts (Comprehensions)

Objectives

Python is famous for its clean and readable syntax. One of the best examples of this is comprehensions. A comprehension is a compact way to create a new list, set, or dictionary from an existing sequence. It lets you replace a multi-line `for` loop with a single, elegant line of code. For example, instead of creating an empty list and looping to add the square of each number, you can just write squares = [n*n for n in numbers].

Python also has tools for a style of programming called "functional programming." Two key functions here are map and filter. `map` applies a function to every single item in a list (e.g., convert a list of strings to all lowercase). `filter` creates a new list containing only the items from an original list that pass a certain test (e.g., keep only the numbers greater than 10).

Sometimes, the function you want to use with `map`, `filter`, or sorting is so simple that it feels silly to define it with `def`. For these one-off uses, Python gives you lambda functions. They are small, anonymous (unnamed) functions that you can define right where you need them. They are perfect for short, simple operations.

🤯 This sounds very abstract. What's a simple way to get it?

A list comprehension is like giving a command to a whole group at once.

Imagine you have a room full of people and you want a list of everyone's name in uppercase.

  • The for loop way: You go to each person individually and say, "What's your name? Okay, now I'll write it down in uppercase." This takes a while.
  • The comprehension way: You stand at the front of the room and shout, "Give me a list of [person.name.upper() for person in this_room]!". You get the result instantly. It's a single, powerful command to build a new list.

A lambda function is like a Post-it note instruction. It's a small, disposable function. You don't need to give it a formal name with `def` because you're only going to use it this one time.

Practice ✍️

You have a list of numbers: nums = [1, 2, 3, 4, 5, 6]. Use a list comprehension to create a new list containing only the even numbers from the original list. Then, use another list comprehension to create a list of the squares of those even numbers.

Click to reveal sample comprehensions
# comprehension_practice.py
nums = [1, 2, 3, 4, 5, 6]

# 1. Use a list comprehension with a condition to get even numbers
even_numbers = [n for n in nums if n % 2 == 0]
print(f"Even numbers: {even_numbers}") # Expected: [2, 4, 6]

# 2. Use a list comprehension to square the even numbers
squared_evens = [n*n for n in even_numbers]
print(f"Squared evens: {squared_evens}") # Expected: [4, 16, 36]
        

Day 15: Setting Up Your Project Workshop (Virtual Environments)

Objectives

Imagine working on two different projects. Project A needs an old version of a library, but Project B needs the newest version. If you install them both on your main computer, they'll conflict! This is a common headache, and the solution is virtual environments.

A virtual environment is an isolated, self-contained directory for your project. It has its own Python interpreter and its own set of installed packages. This means you can create a separate, clean workshop for every project you work on, and the tools (packages) from one won't interfere with another. It's a best practice that will save you countless problems down the line. You can create one easily with the command: python3 -m venv venv.

Once your environment is "activated," you can use `pip` to install packages just for that project. To make your project easy for others to use, you can create a list of all the packages it needs. The standard way to do this is with a requirements.txt file. You can generate it with one command (pip freeze > requirements.txt), and anyone else can then install all the necessary packages with another (pip install -r requirements.txt).

🤯 Why do I need this extra step? An analogy for your workshop.

A virtual environment is a dedicated, clean workshop for each project. 🛠️

Imagine you're a builder.

  • On Monday, you're building a delicate birdhouse. You need small nails, wood glue, and fine-grit sandpaper. This is Project A.
  • On Tuesday, you're building a heavy-duty fence. You need huge bolts, a power drill, and concrete mix. This is Project B.

Would you want all those tools dumped together on one workbench? Of course not! You'd have a separate setup for each job. A virtual environment does exactly that for your Python projects. It gives each one its own clean workbench with only the specific tools (packages) it needs.

The requirements.txt file is just the official list of tools you need for that specific job, so another builder can set up their workshop exactly like yours.

Practice ✍️

Time to put it all together. Create a new project folder. Inside it, create a new virtual environment and activate it. Once activated, use `pip` to install the `requests` library. Check that it installed correctly. Finally, create the `requirements.txt` file for your project.

Click to view sample steps and commands
# On your command line / terminal:

# 1. Create a new folder and move into it
mkdir my-new-project
cd my-new-project

# 2. Create the virtual environment (this creates a 'venv' folder)
python3 -m venv venv

# 3. Activate the environment
# On macOS/Linux:
source venv/bin/activate
# On Windows:
venv\Scripts\activate
# (Your prompt should now change to show '(venv)')

# 4. Install a package
pip install requests

# 5. Create the requirements file
pip freeze > requirements.txt

# 6. When you're done, deactivate the environment
deactivate
        

Further resources