Packages, __init__.py and if __name__ == "__main__"
- Explain what a Package is and build one with
__init__.py - Import modules and functions from inside a Package
- Explain what the value of
__name__is when a file is run versus when it is imported - Use
if __name__ == "__main__":to separate a “library” from a “program”
What will we learn?
- Package — a folder that contains modules.
- The file
__init__.pyand its role. - Importing from inside a Package.
- The special variable
__name__, and the patternif __name__ == "__main__":.
Why do we need this?
When there are 3 modules, they can sit in the same folder. When there are 30, you need folders: everything related to users in one folder, everything related to payments in another. That is how all real projects are built, and also all the libraries you will install (FastAPI is a huge Package with dozens of sub-Packages).
And if __name__ == "__main__": solves the problem from the previous lesson: test code that runs every time someone imports the file.
Explanation from the basics
Package = a folder of modules
A Package is a folder that contains modules (.py files), and usually also a file named __init__.py.
store/ ← project folder
├── main.py ← the program you run
└── inventory/ ← a PACKAGE
├── __init__.py ← marks this folder as a package
├── products.py ← module
└── stock.py ← module__init__.py
- Marks the folder as a Package, explicitly and clearly.
- Runs automatically the first time something is imported from the Package.
- Usually empty. You can put convenient imports in it, so that you can write
from inventory import add_productinstead offrom inventory.products import add_product.
(In modern Python you can also import from a folder without __init__.py, but the accepted convention is to include it, so that it is clear this is a package and not just a folder.)
Importing from a Package
The dot separates a folder from a module, exactly like / in a path:
import inventory.products # inventory/products.py
from inventory import products # same module, shorter use
from inventory.products import add_product # one function__name__ — “who am I?”
Every module has a built-in variable named __name__. Python sets its value according to how the file was started:
| How the file was started | The value of __name__ |
|---|---|
Run directly: python prices.py | "__main__" |
Imported from another file: import prices | "prices" (the module’s name) |
And therefore:
if __name__ == "__main__":
# runs ONLY when this file is run directly, NOT when it is importedA chef cooks in their own restaurant (running directly), and at the same time sells sauces to shops (importing). When they are in the restaurant, they also serve customers: that is the code inside if __name__ == "__main__". When a shop buys a sauce, it gets only the sauce (the functions), and not a whole meal forced on it.
Syntax
project/
├── main.py
└── package_name/
├── __init__.py
└── module_name.py# main.py
from package_name.module_name import some_function
from package_name import module_name
# any module that can also be run directly:
def main():
... # what happens when the file is run as a program
if __name__ == "__main__":
main()The pattern of a main() function + the condition at the end of the file is the standard in every Python file meant to be run.
First code example
Let’s see __name__ in action. week-2/name_demo/greetings.py:
def hello(name):
return "Hello, " + name + "!"
print("greetings.py: __name__ is", __name__)
if __name__ == "__main__":
print("Running greetings.py directly - quick self test:")
print(hello("Tester"))week-2/name_demo/app.py:
import greetings
print("app.py: __name__ is", __name__)
print(greetings.hello("Dana"))Run 1: python greetings.py
greetings.py: __name__ is __main__
Running greetings.py directly - quick self test:
Hello, Tester!Run 2: python app.py
greetings.py: __name__ is greetings
app.py: __name__ is __main__
Hello, Dana!Breaking down the code line by line
Run 1 (python greetings.py) | Run 2 (python app.py) | |
|---|---|---|
__name__ of greetings.py | "__main__" (it is the file that was run) | "greetings" (it was imported) |
The first print in greetings | Runs | Runs (code at the top level always runs on import) |
The if __name__ == "__main__" block | Runs (self test) | Does not run |
__name__ of app.py | — | "__main__" |
The conclusion: everything that should run only when the file is run directly (tests, demos, starting the program) goes inside the condition. Definitions of functions and constants stay outside, so that they can be imported.
Another example
A project with a real Package. The structure:
week-2/store/
├── main.py
└── inventory/
├── __init__.py
├── products.py
└── stock.pyinventory/__init__.py:
from inventory.products import create_product
from inventory.stock import add_stock, remove_stockinventory/products.py:
def create_product(name, price):
if price < 0:
raise ValueError("price cannot be negative, got " + str(price))
return {"name": name, "price": price, "quantity": 0}
if __name__ == "__main__":
print(create_product("Test item", 10))inventory/stock.py:
def add_stock(product, amount):
product["quantity"] = product["quantity"] + amount
def remove_stock(product, amount):
if amount > product["quantity"]:
raise ValueError("not enough " + product["name"] + " in stock")
product["quantity"] = product["quantity"] - amountmain.py:
from inventory import create_product, add_stock, remove_stock
def main():
laptop = create_product("Laptop", 3500)
add_stock(laptop, 10)
remove_stock(laptop, 3)
print(laptop)
try:
remove_stock(laptop, 50)
except ValueError as error:
print("Error:", error)
if __name__ == "__main__":
main()Run (from week-2/store): python main.py
{'name': 'Laptop', 'price': 3500, 'quantity': 7}
Error: not enough Laptop in stockBreakdown:
__init__.pygathers the important functions of the Package. Thanks to it,main.pywritesfrom inventory import create_product, and does not need to know which internal file exactly it sits in. From outside, the Package looks like “one unit”.add_stock(laptop, 10)changes the dict itself, because a dict is Mutable (the data structures and functions topic!). The function does not need to return anything.products.pyincludes a self test insideif __name__ == "__main__". You can run it alone to test it, and it does not “make a mess” when it is imported.main.pyis wrapped inmain()+ the condition. If someone imports it in the future, nothing will run by itself.
If you try python inventory/products.py, you sometimes get a ModuleNotFoundError, because Python looks for modules from the folder of the file that was run (inventory/), and not from the project folder. The right way to run a module inside a Package is from the project folder, with the -m (module) flag and dots instead of slashes: python -m inventory.products.
Common mistake
Mistake 1: writing "main" instead of "__main__".
if __name__ == "main":
main()Nothing runs, and there is no error! The value is "__main__", with two underscores on each side. A silent Logical Error.
Mistake 2: a Circular Import.
a.py imports b, and b.py imports a:
ImportError: cannot import name 'x' from partially initialized module 'a' (most likely due to a circular import)Two modules that depend on each other are a sign of a bad split. Move the shared part into a third module, which both of them import from.
Mistake 3: putting all the logic inside the if block.
if __name__ == "__main__":
def calculate(x):
return x * 2
print(calculate(5))Now calculate cannot be imported from another file, because it is defined only when the file is run directly. The functions go outside, and only starting the program goes inside.
Practice
The exercises use only what was taught in this lesson and the lessons before it. Try on your own first, and only then open the solution.
Exercise 1: The structure of a Package
Draw the folder structure of a project store with a file main.py and a Package named inventory, which has two modules: products.py and stock.py. Which file must be inside inventory, and why?
Show solution
store/
├── main.py
└── inventory/
├── __init__.py
├── products.py
└── stock.py__init__.py marks the folder as a Package — a folder of modules that you can import from. It can be empty.
Exercise 2: Importing from a Package
In inventory/products.py there is a function create_product(name, price) that returns a dictionary. Write in main.py three ways to import it and use it.
Show solution
import inventory.products
laptop = inventory.products.create_product("Laptop", 3500)
from inventory import products
mouse = products.create_product("Mouse", 80)
from inventory.products import create_product
desk = create_product("Desk", 900)The dot in the path (inventory.products) is like / in folders: the module products inside the Package inventory.
Exercise 3: What is name?
In the file greetings.py:
def hello(name):
return "Hello, " + name + "!"
print("__name__ is", __name__)What will be printed in each case?
- You run
python greetings.py. - You run
main.py, which containsimport greetings.
Show solution
- When run directly:
__name__ is __main__. - When imported:
__name__ is greetings— the module’s name.
Python sets __name__ according to how the file was started. That is the basis of the main guard.
Exercise 4: The main guard
Add to greetings.py (from the previous exercise, with the function hello) a self test that runs only when the file is run directly, and not when it is imported. The test prints quick self test: and then the result of hello("Tester").
Delete the line print("__name__ is", __name__) from the previous exercise.
Expected output (python greetings.py):
quick self test:
Hello, Tester!Show solution
def hello(name):
return "Hello, " + name + "!"
if __name__ == "__main__":
print("quick self test:")
print(hello("Tester"))quick self test:
Hello, Tester!When another file does import greetings, the condition is False — the test does not run, and only the function is available.
Exercise 5: The mathtools package
Build a Package named mathtools with two modules: basic.py with add(a, b), and stats.py with mean(numbers) and maximum(numbers). In main.py, use all three.
add(2, 3)
mean([10, 20, 30])
maximum([10, 20, 30])Expected output:
add: 5
mean: 20.0
maximum: 30Show solution
math_project/
├── main.py
└── mathtools/
├── __init__.py
├── basic.py
└── stats.pymathtools/basic.py
def add(a, b):
return a + bmathtools/stats.py
def mean(numbers):
return sum(numbers) / len(numbers)
def maximum(numbers):
return max(numbers)main.py
from mathtools.basic import add
from mathtools import stats
print("add:", add(2, 3))
print("mean:", stats.mean([10, 20, 30]))
print("maximum:", stats.maximum([10, 20, 30]))Summary
- Package = a folder of modules, with an
__init__.pythat runs on the first import and can “expose” convenient names. - Importing from a Package:
from package.module import name. The dot = going into a folder. __name__is"__main__"when the file was run directly, and the module’s name when it was imported.if __name__ == "__main__": main()— start the program only when run directly. Define functions outside.- A module inside a Package is run from the project folder with
python -m package.module.