Modules and Imports in Python

Modules are files containing Python code that can be imported and used in other Python programs. They help organize code into reusable components and enable code sharing across multiple projects. Python's import system makes it easy to incorporate functionality from the standard library, third-party packages, or your own custom modules.

Import Fundamentals

Basic Import Types

Python offers several ways to import modules or specific objects from modules.

# Standard import
import math
print(math.sqrt(16))  # 4.0

# Import with alias
import math as m
print(m.sqrt(16))  # 4.0

# Import specific objects from a module
from math import sqrt, pi
print(sqrt(16))  # 4.0
print(pi)        # 3.141592653589793

# Import specific objects with aliases
from math import sqrt as square_root
print(square_root(16))  # 4.0

# Import all objects from a module (not recommended)
from math import *
print(sqrt(16))  # 4.0
print(cos(0))    # 1.0

Module Attributes

Modules have special attributes that provide information about them.

# Common module attributes
import math

print(math.__name__)      # 'math' - The module's name
print(math.__file__)      # Path to the module file
print(math.__doc__)       # Module's docstring
print(dir(math))          # List of names defined in the module

# The __all__ attribute controls what is imported with 'from module import *'
# Example of how it works in a custom module:
"""
# mymodule.py
__all__ = ['public_function', 'PublicClass']

def public_function():
    pass
    
def _private_function():  # Won't be imported with 'from mymodule import *'
    pass
    
class PublicClass:
    pass
"""

Creating and Organizing Modules

Creating Your Own Modules

Any Python file can be a module that other Python scripts can import.

# File: mymath.py
"""
Custom math operations module.

This module provides additional math functions
not found in the standard math module.
"""

PI = 3.14159

def square(x):
    """Return the square of a number."""
    return x * x

def cube(x):
    """Return the cube of a number."""
    return x * x * x

if __name__ == "__main__":
    # This code runs only when the file is executed directly
    # and not when imported as a module
    print("Testing mymath module")
    print(f"Square of 4: {square(4)}")
    print(f"Cube of 3: {cube(3)}")

# In another file:
# import mymath
# print(mymath.square(5))  # 25

Working with Packages

Packages are directories containing Python modules and a special __init__.py file. They help organize related modules into a hierarchical structure.

# Package structure example
"""
mypackage/                  # Root package
    __init__.py             # Makes mypackage a package
    module1.py              # Regular module
    module2.py              # Regular module
    subpackage/             # Subpackage
        __init__.py         # Makes subpackage a package
        module3.py          # Module in subpackage
        module4.py          # Module in subpackage
"""

# The __init__.py file can be empty or contain initialization code
# File: mypackage/__init__.py
"""
This is the mypackage package.
"""
print("Initializing mypackage")

# You can also use __init__.py to expose specific modules/objects
from mypackage.module1 import function1
from mypackage.module2 import function2
from mypackage.subpackage.module3 import function3

# Using the package
# import mypackage
# mypackage.function1()

# from mypackage import module1
# module1.function1()

# from mypackage.subpackage import module3
# module3.function3()

Relative Imports

Within a package, you can use relative imports to reference other modules in the same package.

# Relative imports
# File: mypackage/subpackage/module4.py

# Import from the same directory
from . import module3
# or
from .module3 import function3

# Import from parent package
from .. import module1
# or
from ..module1 import function1

# Import from sibling package
from ..othersubpackage import module5

# Note: Relative imports can only be used inside packages
# and cannot be used in scripts run directly with python

Python's Import System

Module Search Path

When you import a module, Python searches for it in multiple locations in a specific order.

# Python searches for modules in the following order:
# 1. The directory containing the script being run
# 2. Directories in the PYTHONPATH environment variable
# 3. Standard library directories
# 4. Directories of installed packages

# The search path is stored in sys.path
import sys
print(sys.path)

# You can add a directory to the search path
import sys
sys.path.append('/path/to/my/modules')
import my_custom_module

# Safer alternative: use site-packages or a .pth file

Import Mechanics

Understanding how Python's import system works behind the scenes.

# What happens during import:
# 1. Find the module (search in sys.path)
# 2. Create a new module object
# 3. Execute the module code in the new module's namespace
# 4. Store the module object in sys.modules cache

# Subsequent imports use the cached module
import sys
print('math' in sys.modules)  # False (if not imported yet)
import math
print('math' in sys.modules)  # True

# Reloading a module (rarely needed)
import importlib
import math
importlib.reload(math)

Standard Library Modules

Python's standard library includes a vast collection of modules covering many common programming tasks. Here are some essential modules you should know:

Module Purpose Common Use
os Operating system interface File operations, environment variables
sys System-specific parameters Command line args, Python internals
datetime Date and time handling Creating and manipulating dates/times
math Mathematical functions Trigonometry, rounding, etc.
random Random number generation Generating random values, shuffling
json JSON encoding/decoding Working with JSON data
re Regular expressions Pattern matching in strings
# Examples of common standard library modules

# os: Operating system interfaces
import os
current_dir = os.getcwd()
files = os.listdir('.')
os.mkdir('new_directory')

# datetime: Date and time handling
from datetime import datetime, timedelta
now = datetime.now()
tomorrow = now + timedelta(days=1)

# json: JSON encoding and decoding
import json
data = {'name': 'John', 'age': 30}
json_string = json.dumps(data)
parsed_data = json.loads(json_string)

Best Practices

Import Style Guidelines

  • Put all imports at the top of the file
  • Group imports in this order: standard library, third-party, local modules
  • Use separate lines for each import
  • Avoid wildcard imports (from module import *)
  • Be explicit about what you're importing
  • Use absolute imports when possible
# Good import style
# Standard library imports
import os
import sys
from datetime import datetime

# Third-party imports
import numpy as np
import pandas as pd

# Local/application imports
from myapp.models import User
from myapp.utils import helper_function

Module Design Tips

  • Keep modules focused on a single purpose or functionality
  • Use docstrings to document modules, classes, and functions
  • Use `__all__` to explicitly define the public API
  • Prefix internal-use functions and variables with an underscore
  • Structure large applications as packages with clear hierarchies
  • Test modules independently for better modularity

Practice Exercises

Try These:

  1. Create a module with utility functions for string manipulation and import it in another script.
  2. Create a package with modules for different algorithms (sorting, searching, etc.).
  3. Write a script that dynamically imports a module based on a command-line argument.
  4. Create a module that uses relative imports within a package hierarchy.
  5. Implement a lazy loading mechanism for a module with expensive initialization.
Back to Cheat Sheet