🧩 Learn how to organize and reuse Python code using modules and packages — essential tools for building scalable, maintainable applications.
This section explains how to:
- Break your program into multiple files (modules)
- Organize modules into packages
- Use
importeffectively - Understand the module search path
- Control script vs module behavior using
__name__ - Create private functions in modules
- Work with subpackages and nested imports
A module is a .py file that contains reusable Python code — such as functions, classes, or variables.
🔹 Why use modules?
- Reuse code across multiple programs.
- Keep your codebase organized.
- Improve readability and maintainability.
- Share functionality across teams.
🔹 Example: pricing.py
# pricing.py
def get_net_price(price, tax_rate, discount=0):
discounted_price = price * (1 - discount)
return discounted_price * (1 + tax_rate)
def get_tax(price, tax_rate=0):
return price * tax_rate🔹 Using the Module in Another File:
# main.py
import pricing
net_price = pricing.get_net_price(100, 0.1)
print(f"Net Price: {net_price}")There are several ways to import modules depending on what you need:
import module_nameimport module_name as aliasfrom module import function, variablefrom module import *🔸 Best Practices:
- Avoid
import *— it pollutes the namespace and can cause conflicts. - Use explicit imports like
from module import functionfor clarity. - Use aliases when importing long/namespaced modules:
import very_long_module_name as mod
When you import a module, Python searches for it in the following order:
- The current directory.
- Directories listed in the
PYTHONPATHenvironment variable. - Installation-dependent standard library paths.
🔹 You can view the search path with:
import sys
for path in sys.path:
print(path)🔸 Modifying the Path at Runtime:
sys.path.append('/path/to/your/module')Python doesn’t have true private functions, but there are conventions and techniques to simulate privacy.
Prefix a function name with an underscore _ to indicate it's intended as private.
🔹 Example:
# mail.py
def send(email, message):
print(f'Sending "{message}" to {email}')
def _attach_file(filename):
print(f'Attach {filename} to message')🔸 Now, send() is public; _attach_file() signals internal use.
Define __all__ in your module to specify which names should be exported by import *.
🔹 Example:
# mail.py
__all__ = ['send']
def send(email, message):
...
def attach_file(filename):
...🔸 With this setup, from mail import * will only expose send().
Every Python module has a built-in variable called __name__. It tells you whether the module is being run directly or imported.
🔹 Use Case – Run Code Only When Script is Executed:
# hello.py
def greet():
print("Hello from Hello module!")
if __name__ == "__main__":
greet()🔸 Behavior:
- If run directly:
python hello.py→ "Hello from Hello module!" - If imported:
import hello→ no output
💡 This pattern is widely used in testable modules and CLI scripts.
A package is a way to organize related modules into a directory hierarchy.
🔹 To create a package:
- Make a folder
- Add an
__init__.pyfile (can be empty) - Place your module files inside
📁 Folder structure:
sales/
├── __init__.py
├── order.py
├── delivery.py
└── billing.py
🔹 Importing from a Package:
import sales.order
from sales.billing import generate_invoice🔸 You can also rename imports:
from sales.delivery import ship_order as start_shippingThe __init__.py file makes Python treat a directory as a package.
🔹 You can define:
- Default variables
- Auto-import modules
- Define
__all__for wildcard imports
🔹 Example:
# sales/__init__.py
TAX_RATE = 0.07
from .order import place_order
from .delivery import schedule_delivery🔸 Now, these are available directly from the package:
import sales
sales.place_order(...)Packages can contain subpackages, allowing deeper levels of organization.
📁 Example:
sales/
├── __init__.py
├── order/
│ ├── __init__.py
│ └── process.py
├── delivery/
│ ├── __init__.py
│ └── logistics.py
🔹 Importing from subpackages:
from sales.order.process import new_order🔸 Just like top-level packages, subpackages can also have their own __init__.py files for initialization logic.
You can control what gets exposed when someone uses from package import *.
🔹 Example:
# sales/__init__.py
__all__ = ['order', 'delivery']Now only order and delivery will be available via:
from sales import *Modules and packages help you build modular, reusable codebases.
🔹 Benefits:
- Reusability: write once, use everywhere.
- Maintainability: isolate changes to one file.
- Readability: group related functionality together.
- Scalability: manage large projects more easily.
🔹 Best Practices:
- Group related modules into packages.
- Keep each module focused on one task.
- Use descriptive naming.
- Document each module and function.
📁 Structure:
pricing/
├── __init__.py
├── tax.py
└── discount.py
🔹 tax.py:
def calculate_tax(amount, rate):
return amount * rate🔹 discount.py:
def apply_discount(amount, percent):
return amount * (1 - percent / 100)🔹 Usage:
from pricing.tax import calculate_tax
from pricing.discount import apply_discount
price = apply_discount(100, 10) # $90
tax = calculate_tax(price, 0.10) # $9.00🧠 Hidden Tips & Notes
- 🧩 A module can be both executable and importable — use the
if __name__ == '__main__':idiom. - 📁 Starting with Python 3.3+, you can have namespace packages without
__init__.py. - 🧵 Avoid deep nesting — keep your package structure shallow and logical.
- 🔒 Use
_prefix or__all__to make functions "private". - 🔄 Use relative imports within packages (
from . import module) for better portability. - 📂 Always include
__init__.pyunless you're intentionally creating a namespace package. - 🧹 Don't abuse
import *— it reduces clarity and increases bugs.
| Concept | Description |
|---|---|
| Module | A single .py file containing Python definitions |
| Package | A folder containing modules and an __init__.py |
| Import Statement | import module, from module import function, etc. |
| Search Path | Where Python looks for modules — controlled by sys.path |
| `name == 'main' | Check if file is run directly or imported |
| Private Functions | Use _function or __all__ to hide internals |
| Subpackages | Nested packages for organizing larger applications |
🎉 Congratulations! You now understand how to organize your Python code into modules and packages, control visibility, and create reusable libraries.
Next up: 📄 Section 12: Working with Files – learn how to read from and write to files, work with CSV data, and interact with your filesystem.