Skip to Content
Course content

156: Organizing Code into Modules

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Up until now, we've been writing our code in single files. That works fine for a script that does one thing, but as soon as your project grows, your file becomes a "junk drawer." You spend more time scrolling up and down looking for a specific function than you do actually writing code. This is where modules come in.

Think of a module as just a Python file that contains functions, classes, or variables that you want to use in other parts of your program. It's about separation of concerns: one file handles the "how" (the logic), and another file handles the "when" (the execution).

Defining our conversion logic

I'm going to build a small utility that handles different types of conversions—temperature and currency. Instead of putting everything in one place, I'll create a dedicated file called converters.py. This file isn't meant to "run" on its own; it's a toolbox for other scripts to use.

# converters.py
def celsius_to_fahrenheit(celsius):
    return (celsius * 9/5) + 32

def fahrenheit_to_celsius(fahrenheit):
    return (fahrenheit - 32) * 5/9

def usd_to_eur(amount, exchange_rate=0.92):
    return amount * exchange_rate

Simple enough. No fancy logic here, just pure utility functions. Now, I want to actually use these in a separate script, which I'll call app.py.

Pulling tools from the toolbox

Now I'll create app.py. This is where the user interaction happens. I have two main ways to import my module: I can import the whole thing, or just the specific functions I need. I personally prefer importing specific functions because it makes it obvious where a function came from when you're reading the code six months later.

# app.py
from converters import celsius_to_fahrenheit, usd_to_eur

temp_c = 25
temp_f = celsius_to_fahrenheit(temp_c)
print(f"{temp_c}°C is {temp_f}°F")

dollars = 100
euros = usd_to_eur(dollars)
print(f"${dollars} is approximately €{euros}")

The "Accidental Execution" mistake

Here is where I usually trip up when I'm moving fast. Let's say I wanted to test my converters.py file while I was writing it, so I added some print statements at the bottom of that file to make sure the math was right.

# converters.py (Modified)
def celsius_to_fahrenheit(celsius):
    return (celsius * 9/5) + 32

# ... other functions ...

print("Testing Celsius to Fahrenheit: 25C should be 77F")
print(celsius_to_fahrenheit(25))

The problem? Now, every time I run app.py, those test prints from converters.py show up in my console. Why? Because when Python imports a module, it executes the entire file. It doesn't know that those print statements were just for my own temporary testing.

Using the main guard

To fix this, we use a special Python idiom: the if __name__ == "__main__": block. This tells Python: "Only run this code if this file is being executed directly. If this file is being imported as a module, ignore this part."

I'll move my tests into that block in converters.py:

# converters.py (Fixed)
def celsius_to_fahrenheit(celsius):
    return (celsius * 9/5) + 32

def fahrenheit_to_celsius(fahrenheit):
    return (fahrenheit - 32) * 5/9

def usd_to_eur(amount, exchange_rate=0.92):
    return amount * exchange_rate

if __name__ == "__main__":
    # This only runs if I do 'python converters.py'
    # It will NOT run if I do 'import converters' in app.py
    print("Running internal module tests...")
    print(f"Test: 25C -> {celsius_to_fahrenheit(25)}F")

Now app.py stays clean, but I still have a way to quickly verify my logic by running the module file directly. It's a small habit that saves a lot of debugging headaches in larger projects.




📋 Practical Task

Build a Modular Geometry Calculator

You need to create a small project consisting of two files to calculate areas of different shapes.

  1. Create a file named geometry.py. In this file, define two functions: calculate_circle_area(radius) and calculate_rectangle_area(length, width).
  2. At the bottom of geometry.py, implement an if __name__ == "__main__": block that prints the result of a circle with radius 5 and a rectangle with 10x5 dimensions.
  3. Create a second file named main.py. Import both functions from the geometry module and use them to calculate the area of a circle with radius 12 and a rectangle with 7x3 dimensions. Print the results with descriptive labels.
  4. Run main.py and verify that the internal tests from geometry.py do not appear in the output.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.