Python Modules & Packages
Core Definitions
| Term | Definition |
|---|---|
| Module | Any .py file |
| Package | A directory containing an __init__.py file and Python modules |
| Main module | The module that is directly run (its __name__ equals "__main__") |
Modules
Naming Conventions
- Use snake_case (lowercase with underscores)
- No spaces, no special characters
- Avoid names that clash with built-in modules (e.g. don't name your file
math.py)
Checking the Module Name
print(__name__) # prints "__main__" if this file was run directly
# prints the module name (e.g. "functions") if it was imported
Importing Modules
Given a file functions.py in the same directory containing:
def foo():
print("foo")
def bar():
print("bar")
class Test:
pass
1. Import the whole module (use prefix to access)
import functions
functions.foo() # foo
functions.bar() # bar
t = functions.Test()
2. Import with an alias
import functions as f
f.foo() # foo
# functions.foo() — no longer works
3. Import specific items (no prefix needed)
from functions import foo, bar, Test
foo() # foo
bar() # bar
4. Import everything (use with caution ⚠️)
from functions import *
foo() # works — but risky
⚠️ Avoid
import *unless you truly need everything. It can cause name conflicts and makes code harder to read.
Import Placement
Always put imports at the top of the file. Importing after usage causes a NameError:
f.foo() # ❌ NameError — f not defined yet
import functions as f
What Happens When You Import a Module
When a module is imported, all the code inside it runs once. This is why:
- A print("ran") inside functions.py will print when you import it
- Circular imports cause infinite loops (see below)
Circular Imports
A circular import happens when module A imports module B, and module B also imports module A:
modules_and_packages.py → imports → functions.py
functions.py → imports → modules_and_packages.py
This creates an infinite loop because importing triggers all code to run. Avoid this by having one main module that imports from others — not modules importing each other.
if __name__ == "__main__"
Use this guard to run code only when the file is executed directly, not when it's imported:
def foo():
print("foo")
if __name__ == "__main__":
print("Running directly!") # only runs if this file is the main module
foo()
When imported, __name__ is the module's filename (e.g. "functions"), so the block is skipped.
Packages
Creating a Package
A directory becomes a package by adding an __init__.py file inside it:
my_project/
│
├── main_module.py
└── code/ ← package (has __init__.py)
├── __init__.py
├── a.py
└── b.py
Without __init__.py → just a folder. With it → a Python package.
__init__.py
- Runs automatically whenever the package is imported
- Can be left empty, or used to pre-import things from the package
# code/__init__.py
from code.a import a # now accessible as code.a directly
from code.b import b
Importing from Packages
Absolute Imports (recommended ✅)
Specify the full path from the top-level package:
import code.a # import the module
code.a.a() # call function a from module a
from code.a import a # import the function directly
a()
from code import a, b # works if __init__.py imports them
Nested packages
main/
├── a/
│ └── p1/
│ └── run_code.py
└── b/
└── p2/
└── print_something.py
import main.a.p1.run_code
from main.b.p2 import print_something
Relative Imports (advanced, use sparingly ⚠️)
Relative imports use dots to indicate location relative to the current file:
from . import b # import b from the current package
from .. import b # go one level up, then import b
from ...b.p2 import x # go two levels up, into b/p2, import x
Rules:
- Must use from ... import syntax (can't do import ...module)
- Only works when the file is part of an imported package — not when run directly
- Generally considered less readable than absolute imports — prefer absolute imports
Summary: Key Rules
| Rule | Detail |
|---|---|
Module = .py file |
Any Python file is a module |
Package = directory + __init__.py |
The init file makes it a package |
| Import runs code once | All code in a module runs the first time it's imported |
| Avoid circular imports | Don't have two modules import each other |
Use if __name__ == "__main__" |
To protect code that should only run when executed directly |
| Prefer absolute imports | Clearer, less error-prone than relative imports |
| Name modules in snake_case | No spaces, no special characters, no clashes with built-ins |