PYTHON • GETTING STARTED AND TOOLING

Modules vs. Scripts — Explain modules vs scripts and how __name__ == '__main__' works (conceptual)

Understand when Python runs your code directly and when it borrows it from another file.

Historical Context & Motivation

In the earliest days of programming, a program was just one long file of instructions executed from top to bottom. As software became more complex, developers realized they needed a way to split code into smaller, reusable pieces. Python, created by Guido van Rossum in the late 1980s, adopted the concept of modules from earlier languages to solve this exact problem. Modules let you write a function once and reuse it across many programs, rather than copying and pasting code everywhere.

1960s
Subroutine Libraries
Early languages like FORTRAN introduced the idea of reusable subroutine libraries, letting programmers share commonly used mathematical functions across projects.
1991
Python 0.9 Released
Guido van Rossum released Python with a built-in module system and the import statement, inspired by Modula-3's clean module design.
2000
Python 2.0 & Packages
Python 2.0 formalized packages — folders of modules — and introduced __init__.py files, making large-scale code organization standard practice.
2008
Python 3 & Modern Imports
Python 3 cleaned up the import system and made the if __name__ == '__main__' guard a widely taught best practice for writing dual-purpose files.
2020s
PyPI Ecosystem Explodes
The Python Package Index (PyPI) now hosts over 400,000 third-party modules, demonstrating how central the module concept is to modern Python development.

The core question that drove all of this evolution is simple: How can Python tell whether a file is being run directly by a user, or being borrowed by another file? The answer lies in a special variable called __name__, and understanding it is one of the most important steps in learning to write clean, reusable Python code.

Core Principles & Definitions

Before diving deeper, you need to understand a few foundational ideas. Every .py file you create in Python can serve two roles: it can act as a script (a program you run directly) or as a module (a toolbox of functions and variables that another file imports). The same file can even play both roles depending on how it is used.

1

Script

A Python file that is run directly from the terminal or IDE. When you type python my_file.py, that file is acting as a script. Python executes every line from top to bottom.
2

Module

A Python file that is imported by another file using the import statement. The importing file borrows functions, classes, or variables from the module without running the module's main logic.
3

The __name__ Variable

A built-in variable Python sets automatically. If the file is run directly, __name__ is set to "__main__". If the file is imported, __name__ is set to the module's filename (without .py).
4

The Main Guard

The pattern if __name__ == '__main__': is called the main guard. Code inside this block runs only when the file is executed as a script, not when it's imported as a module.
✦ KEY TAKEAWAY
Think of a Python file like a recipe card. When you cook from the card yourself, that's using it as a script. When a friend photocopies just one recipe from your card to use in their own cookbook, they're treating it as a module. The __name__ variable is like a label that tells you whether you're the one cooking (it says __main__) or someone else borrowed your recipe (it says the card's name instead).

Visual Explanation

The diagram below shows exactly what happens when Python encounters a file. The key difference is how Python sets the __name__ variable depending on whether you run the file directly or import it from another file.

When you run python helpers.py directly, Python sets __name__ to "__main__" (left path). When another file writes import helpers, Python sets __name__ to "helpers" (right path). The main guard uses this difference to decide what code to run.

Notice the two paths diverge at the very beginning. Python makes this decision before any of your code runs. By the time the first line of your file executes, __name__ has already been set. The main guard simply checks which value was assigned and decides whether to run certain blocks of code.

How It Works Under the Hood

When you type python my_file.py in the terminal, Python's interpreter does several things behind the scenes before executing your code. Understanding this sequence makes the __name__ behavior feel completely logical rather than magical.

Step-by-Step: Running a File Directly

  1. Step 1: Python reads the file and creates a special namespace (a container for all variables and functions defined in the file).
  2. Step 2: Python sets the built-in variable __name__ to the string "__main__" because this is the entry point — the file you asked Python to run.
  3. Step 3: Python executes every line of the file, top to bottom, including any if __name__ == '__main__': block (because the condition is True).

Step-by-Step: Importing a File as a Module

  1. Step 1: The importing file encounters import helpers. Python finds helpers.py and reads it.
  2. Step 2: Python sets __name__ to "helpers" (the module's filename without the .py extension).
  3. Step 3: Python executes the module's code top to bottom, but the if __name__ == '__main__': block is skipped because "helpers" != "__main__".
  4. Step 4: All function definitions, class definitions, and top-level variables from the module become available in the importing file.
⚠️ Important Detail
When a module is imported, Python still executes the code outside the main guard. This means any print() statements or variable assignments at the top level of the module will still run during import. That's exactly why the main guard exists — to protect code that should only run when the file is used as a script.

The value of __name__ is always a string. There are only two possibilities: it is either "__main__" (run directly) or the module's own name (imported). This simple, binary distinction is what makes the pattern so powerful and reliable.

Anatomy of a Dual-Purpose Python File

A well-structured Python file that can work as both a script and a module follows a predictable layout. The diagram below shows the anatomy of such a file, highlighting which parts execute in each mode.

A dual-purpose file has four sections: imports, function definitions, the main guard, and script-only code. When imported as a module by app.py, only the imports and function definitions execute. The script-only code inside the main guard is skipped entirely.

The key insight is that function definitions are just instructions for creating functions — they don't actually do anything until someone calls them. When app.py imports math_tools, Python reads the def statements and makes those functions available. But because __name__ is "math_tools" (not "__main__"), the print() statement never runs. This is exactly the behavior you want.

Worked Example

Let's walk through a concrete scenario. You have two files: greetings.py (which defines a function) and main_app.py (which imports it). We'll trace what happens in both cases.

Tracing __name__ Across Two Files
1
Step 1 — Write greetings.pyCreate a file called greetings.py with the following code: def say_hello(name): return f"Hello, {name}!" print(f"greetings.py: __name__ is {__name__}") if __name__ == "__main__": message = say_hello("Alice") print(message)
2
Step 2 — Run greetings.py DirectlyIn the terminal, type python greetings.py. Python sets __name__ to "__main__". The diagnostic print runs (it's outside the guard), then the guard condition is True, so the greeting prints too.
Output: greetings.py: __name__ is __main__ Hello, Alice!
3
Step 3 — Write main_app.pyCreate a second file called main_app.py: import greetings print(greetings.say_hello("Bob"))
4
Step 4 — Run main_app.pyType python main_app.py. When Python encounters import greetings, it reads greetings.py and sets its __name__ to "greetings". The diagnostic print on line 4 still runs (it's outside the guard), but the main guard block is skipped. Then main_app.py calls the function and prints its own greeting.
Output: greetings.py: __name__ is greetings Hello, Bob!
5
Step 5 — Key ObservationNotice that "Hello, Alice!" does NOT appear when running main_app.py. The main guard successfully prevented the test code from running during import. However, the unguarded print statement on line 4 still executed — this demonstrates why you should put anything you don't want running on import inside the main guard.
The main guard acts as a gatekeeper, only allowing script-specific code through when the file is the entry point.

Script vs. Module — Side-by-Side Comparison

Now that you understand both modes, let's put them side by side. The table below highlights every key difference between using a Python file as a script versus as a module.

Key differences between Python script mode and module mode
FeatureScript ModeModule Mode
How it startspython filename.pyimport filename
__name__ value"__main__"The file's name (e.g., "filename")
Top-level code runs?Yes, everything executesYes, everything outside the guard executes
Main guard code runs?Yes (condition is True)No (condition is False)
Primary purposeExecute a programProvide reusable functions/classes
Typical use caseRunning a game, app, or automation taskSharing utility functions between projects
✦ KEY TAKEAWAY
Every Python file lives a double life. It's like a Swiss Army knife: when you open it directly, you get the full tool with all its blades extended. When another program imports it, it selectively borrows just the individual tools it needs. The if __name__ == '__main__': guard is the switch that controls which tools are exposed.
💡 Common Beginner Mistake
A frequent error is placing all your code at the top level without a main guard. This means every time someone imports your file, all of that code runs — including test prints, user input prompts, and anything else you only meant to run once. Always wrap your "do stuff" code inside if __name__ == '__main__':.

Connection to Packages and Advanced Organization

Once you master modules and the main guard, the next step is understanding packages. A package is simply a folder of related modules, bundled together with a special file called __init__.py. Packages let you organize large projects into logical groups, like chapters in a book. The same __name__ mechanism works within packages, but the names become dotted paths like "mypackage.helpers".

From modules to packages: building on what you know
ConceptWhat You Learn NowWhat Comes Next
Code organizationSingle file as script or modulePackages (folders of modules)
__name__ value"__main__" or module nameDotted package paths like "pkg.mod"
Running packagespython file.pypython -m package (using __main__.py)
Import styleimport modulefrom package import module
Third-party codeStandard library modulesInstalling packages from PyPI with pip

You might also encounter python -m module_name in tutorials. The -m flag tells Python to find the module in its search path and run it as a script. Even in this case, __name__ is set to "__main__", so the main guard still works exactly as expected. Understanding the basics of scripts and modules gives you a strong foundation for these more advanced tools.

Practice Problems

PROBLEM 1 — CONCEPTUAL
In your own words, explain the difference between a Python script and a Python module. Can a single .py file be both? Why or why not?
PROBLEM 2 — BASIC
Consider a file called utils.py that contains the following code: def double(x): return x * 2 print("utils loaded") if __name__ == "__main__": print(double(7)) What is the exact output when you run python utils.py?
PROBLEM 3 — INTERMEDIATE
Using the same utils.py from Problem 2, now you create a file called app.py with this code: import utils print(utils.double(5)) What is the exact output when you run python app.py? Explain why each line appears (or doesn't appear).
PROBLEM 4 — APPLIED
You're building a temperature converter for a science class project. You want a file called converter.py that defines a celsius_to_fahrenheit(c) function. When run directly, it should convert 100°C and print the result. When imported by your main project file, it should not print anything. Write the complete code for converter.py.
PROBLEM 5 — CRITICAL THINKING
A classmate argues: "The main guard is pointless. I can just put all my code in functions and call them at the bottom of the file. That way nothing runs automatically." Evaluate this claim. Is it correct? Under what circumstances would the main guard still be necessary or preferred?

Lesson Summary

Every Python .py file can serve as a script (run directly) or a module (imported by another file). Python distinguishes between these two roles using the built-in __name__ variable. When a file is run directly, __name__ is automatically set to "__main__". When a file is imported as a module, __name__ is set to the module's filename (without the .py extension).

The main guard pattern — if __name__ == '__main__': — uses this distinction to protect code that should only execute in script mode. Function and class definitions should live outside the guard so they're always available, while test code, print() statements, and program logic go inside it. This pattern lets you create dual-purpose files that work both as standalone programs and as reusable libraries — a fundamental skill for writing clean, professional Python code.

Varsity Tutors • Python • Modules vs. Scripts — Explain modules vs scripts and how __name__ == '__main__' works (conceptual)