🕯️ Magic Note
Every Python file is a module. When you run python my_script.py, you are executing the __main__ module. The name of the module is the filename without the .py extension. This simple fact—that any file can be imported—makes Python incredibly flexible for code organization.
Python
# File: my_math.py (a module)
def add(a, b):
return a + b
def multiply(a, b):
return a * b
PI = 3.14159
# File: main.py (using the module)
# import my_math
#
# result = my_math.add(5, 3)
# print(result) # 8
# print(my_math.PI) # 3.14159
Python
# Method 1: Import the whole module (recommended)
import math
print(math.sqrt(16)) # 4.0
# Method 2: Import specific items
from math import sqrt, pi
print(sqrt(25)) # 5.0
print(pi) # 3.141592653589793
# Method 3: Import with an alias
import numpy as np # Common alias for NumPy
# Often used with third-party libraries
# Method 4: Import everything (not recommended)
from math import *
# Pollutes the namespace, hard to track where names come from
🕯️ Magic Note
The import math statement loads the math module and creates a reference in the current namespace. The module’s contents are accessed via math.sqrt. The from math import sqrt brings sqrt directly into the current namespace. The star import (from math import *) brings all names that do not start with underscore. Avoid star imports in production code.
- 1. The directory containing the script being run
- 2. Directories in the PYTHONPATH environment variable
- 3. Standard library directories
- 4. Site-packages directory (third-party packages)
Python
import sys
print(sys.path) # List of directories Python searches for modules
# You can add directories to the search path
sys.path.append(“/path/to/my/modules”)
Python
# File: my_math.py
def add(a, b):
return a + b
if __name__ == “__main__”:
# This code runs only when the script is executed directly
# Not when it is imported
print(“Testing my_math module”)
result = add(5, 3)
print(f”5 + 3 = {result}”)
🕯️ Magic Note
The if __name__ == “__main__”: guard is a standard pattern. It allows a file to be both a reusable module and a standalone script. You can put test code or example usage inside this block without it running when the module is imported.
Python
# File: string_utils.py
“””
Utility functions for string manipulation.
This module provides helper functions for working with strings.
“””
def reverse_string(text):
“””Return the reverse of a string.”””
return text[::-1]
def is_palindrome(text):
“””Check if a string is a palindrome.”””
cleaned = text.lower().replace(” “, “”)
return cleaned == cleaned[::-1]
def count_vowels(text):
“””Count the number of vowels in a string.”””
vowels = “aeiouAEIOU”
return sum(1 for char in text if char in vowels)
def capitalize_words(text):
“””Capitalize the first letter of each word.”””
return ” “.join(word.capitalize() for word in text.split())
if __name__ == “__main__”:
# Test code
test_string = “hello world”
print(f”Original: {test_string}”)
print(f”Reversed: {reverse_string(test_string)}”)
print(f”Is palindrome ‘racecar’? {is_palindrome(‘racecar’)}”)
print(f”Vowel count: {count_vowels(test_string)}”)
print(f”Capitalized: {capitalize_words(test_string)}”)
# File: main.py (using the module)
import string_utils
text = “A man a plan a canal panama”
print(string_utils.is_palindrome(text)) # True
Python
# Directory structure:
# my_package/
# __init__.py
# math_utils.py
# string_utils.py
# file_utils.py
# File: my_package/__init__.py (can be empty)
# This file tells Python that this directory is a package
# File: my_package/math_utils.py
def add(a, b):
return a + b
# Usage in another file:
# from my_package import math_utils
#
# result = math_utils.add(5, 3)
Python
# Assuming this package structure:
# my_package/
# __init__.py
# math_utils.py
# string_utils.py
# Import a module from a package
import my_package.math_utils
my_package.math_utils.add(5, 3)
# Import a specific function from a module in a package
from my_package.math_utils import add
add(5, 3)
# Import a module with an alias
import my_package.math_utils as mu
mu.add(5, 3)
# Import everything from a module (not recommended)
from my_package.math_utils import *
Python
# File: my_package/math_utils.py
__all__ = [“add”, “multiply”, “PI”]
def add(a, b):
return a + b
def multiply(a, b):
return a * b
def subtract(a, b):
return a – b
PI = 3.14159
# Now, from my_package.math_utils import * will only import
# add, multiply, and PI. subtract will not be imported.
🕯️ Magic Note
The __all__ variable only affects star imports (from module import *). It does not affect other import forms. It is a promise to users: “These are the public names I intend you to use.”
Python
# File: my_package/math_utils.py
def add(a, b):
return a + b
# File: my_package/calculator.py
# Relative import (import sibling module)
from .math_utils import add
# from .. import some_module (parent directory)
def calculate(a, b):
return add(a, b) * 2
Python
# File: my_package/__init__.py
# This code runs when the package is imported
print(“Initializing my_package”)
# Import important names to the package level
from .math_utils import add, multiply
from .string_utils import reverse_string, is_palindrome
# Define what gets imported with “from my_package import *”
__all__ = [“add”, “multiply”, “reverse_string”, “is_palindrome”]
# Package-level variable
VERSION = “1.0.0”
# Now users can do:
# import my_package
# my_package.add(5, 3)
# print(my_package.VERSION)
🕯️ Magic Note
The __init__.py file can be empty, but it is often used to simplify the package interface. Instead of forcing users to write from my_package.math_utils import add, you can import add into the package’s __init__.py so they can write from my_package import add.
Bash
# Install a package
pip install requests
# Install a specific version
pip install requests==2.28.0
# Upgrade a package
pip install –upgrade requests
# Uninstall a package
pip uninstall requests
# List installed packages
pip list
# Install from a requirements file
pip install -r requirements.txt
Text
# requirements.txt example
requests==2.28.0
numpy==1.21.0
pandas>=1.3.0
flask
Bash
# Generate requirements.txt from current environment
pip freeze > requirements.txt
# Install all packages from requirements.txt
pip install -r requirements.txt
Text
my_project/
│
├── my_package/ # The main package
│ ├── __init__.py
│ ├── core.py
│ ├── utils.py
│ └── subpackage/ # Subpackage
│ ├── __init__.py
│ └── helper.py
│
├── tests/ # Unit tests
│ ├── __init__.py
│ ├── test_core.py
│ └── test_utils.py
│
├── scripts/ # Executable scripts
│ └── run.py
│
├── requirements.txt # Dependencies
├── setup.py # For installing the package
└── README.md # Documentation
- Creating circular imports (module A imports module B, module B imports module A)
- Using from module import * in production code (pollutes namespace)
- Name conflicts with standard library modules (naming your module math.py)
- Forgetting the __init__.py file in packages (Python 3.3+ does not require, but still good practice)
- Using relative imports in scripts run directly
- Not using if __name__ == “__main__”: for test code
- How do you create a module?
- What is the purpose of if __name__ == “__main__”:?
- Create a package named shapes with modules circle.py and square.py, each containing an area() function.
- What is the difference between import math and from math import sqrt?
- Why should you avoid from module import *?
- What does the __all__ variable do?
⚡ Whisper
A module is a file. A package is a folder. But these are not just technical details. They are ways to divide your code into meaningful pieces. One module for math utilities. Another for string helpers. Another for file handling. Each has a clear purpose. Each stands alone. Each can be tested, debugged, and improved without touching the others. When you import a module, you are not just loading code. You are making a promise: “This functionality is ready for use.” The module does not care where it is imported from. It does not care who called it. It just does its job and returns. This is modularity. This is reusability. This is how small scripts become large systems. Organize your code into modules. Group modules into packages. Share them across projects. Your future self will thank you. And so will the developers who come after you.