Packages

Learn about Python packages, how they organize modules, and how to create your own packages.

Ali Berro

By Ali Berro

6 min read Section 3
From: Python Fundamentals: From Zero to Hero

Packages

A package is a way of organizing related modules into a single directory hierarchy. Packages help you organize large codebases and create reusable libraries.

What is a Package?

A package is a directory containing:

  • Python modules (.py files)
  • An __init__.py file (makes the directory a package)
  • Optionally, subpackages (nested directories with their own __init__.py)

Package Structure

Here’s a typical package structure:

my_package/
__init__.py
module1.py
module2.py
subpackage/
__init__.py
module3.py
module4.py

The __init__.py File

The __init__.py file makes a directory a Python package. It can be:

  • Empty (just marks the directory as a package)
  • Contains initialization code
  • Controls what gets imported with from package import *

Empty __init__.py

empty-init.py
# __init__.py
# Empty file - just marks directory as package

__init__.py with Initialization

init-with-code.py
# __init__.py
"""My Package - A collection of useful utilities."""
# Import commonly used items
from .module1 import function1, function2
from .module2 import Class1
# Package-level variables
__version__ = "1.0.0"
__author__ = "Your Name"
# Define what gets imported with *
__all__ = ['function1', 'function2', 'Class1']

Creating a Simple Package

Let’s create a simple package step by step:

Step 1: Create Directory Structure

calculator/
__init__.py
basic.py
advanced.py

Step 2: Create Modules

basic.py
# calculator/basic.py
def add(a, b):
return a + b
def subtract(a, b):
return a - b
def multiply(a, b):
return a * b
def divide(a, b):
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b
advanced.py
# calculator/advanced.py
import math
def power(a, b):
return a ** b
def sqrt(a):
return math.sqrt(a)
def factorial(n):
return math.factorial(n)

Step 3: Create __init__.py

calculator-init.py
# calculator/__init__.py
"""Calculator package for basic and advanced operations."""
from .basic import add, subtract, multiply, divide
from .advanced import power, sqrt, factorial
__all__ = ['add', 'subtract', 'multiply', 'divide', 'power', 'sqrt', 'factorial']

Step 4: Use the Package

using-package.py
# Import from package
from calculator import add, multiply, power
result1 = add(5, 3)
result2 = multiply(4, 7)
result3 = power(2, 8)
print(result1) # 8
print(result2) # 28
print(result3) # 256

Package Import Methods

Method 1: Import Package

import-package.py
import calculator
# Access through package name
result = calculator.basic.add(5, 3)

Method 2: Import Module from Package

import-module.py
from calculator import basic
result = basic.add(5, 3)

Method 3: Import Function from Package

import-function.py
from calculator import add
result = add(5, 3)

Method 4: Import from Subpackage

import-subpackage.py
from calculator.advanced import power
result = power(2, 8)

Nested Packages (Subpackages)

You can create packages within packages:

my_package/
__init__.py
utils/
__init__.py
string_utils.py
math_utils.py
data/
__init__.py
processors.py
validators.py

Importing from Subpackages

import-subpackage.py
from my_package.utils import string_utils
from my_package.data import processors
# Or
from my_package.utils.string_utils import function_name

Package Initialization

The __init__.py file runs when the package is first imported:

init-execution.py
# my_package/__init__.py
print("Package is being imported!")
def initialize():
print("Package initialized")
# This runs on import
initialize()

Package-Level Variables

You can define package-level variables in __init__.py:

package-variables.py
# my_package/__init__.py
__version__ = "1.0.0"
__author__ = "Your Name"
__license__ = "MIT"
# Access from outside
# import my_package
# print(my_package.__version__)

Controlling Package Exports

Use __all__ to control what gets imported with from package import *:

package-all.py
# my_package/__init__.py
from .module1 import func1, func2
from .module2 import Class1
# Only these will be imported with *
__all__ = ['func1', 'func2', 'Class1']

Package Example: Math Utilities

Let’s create a complete example:

Directory Structure

math_utils/
__init__.py
basic.py
geometry.py
statistics.py

Module Files

basic.py
# math_utils/basic.py
def add(a, b):
return a + b
def multiply(a, b):
return a * b
geometry.py
# math_utils/geometry.py
import math
def circle_area(radius):
return math.pi * radius ** 2
def rectangle_area(length, width):
return length * width
statistics.py
# math_utils/statistics.py
def mean(numbers):
return sum(numbers) / len(numbers)
def median(numbers):
sorted_nums = sorted(numbers)
n = len(sorted_nums)
if n % 2 == 0:
return (sorted_nums[n//2 - 1] + sorted_nums[n//2]) / 2
return sorted_nums[n//2]

Package Init

math-utils-init.py
# math_utils/__init__.py
"""Math utilities package."""
from .basic import add, multiply
from .geometry import circle_area, rectangle_area
from .statistics import mean, median
__version__ = "1.0.0"
__all__ = ['add', 'multiply', 'circle_area', 'rectangle_area', 'mean', 'median']

Using the Package

using-math-utils.py
from math_utils import add, circle_area, mean
# Basic operations
result = add(5, 3)
print(result) # 8
# Geometry
area = circle_area(5)
print(area) # 78.53981633974483
# Statistics
avg = mean([1, 2, 3, 4, 5])
print(avg) # 3.0

Package Best Practices

  1. Use __init__.py: Always include it, even if empty
  2. Organize logically: Group related modules together
  3. Document packages: Add docstrings to __init__.py
  4. Use __all__: Control what gets exported
  5. Keep it simple: Don’t create unnecessary nesting
  6. Version your packages: Include version info in __init__.py

Package vs Module

  • Module: A single .py file
  • Package: A directory containing multiple modules and an __init__.py file

Exercises

Exercise 1: Understanding Package Structure

Create a simple package structure. You have a package called utils with a module string_utils.py containing a function uppercase(text). Write code to import and use this function. Assume the package structure exists.

Understanding Package Structure

Checks: 0 times
Answer:
utils/
# Assuming utils package exists:
# __init__.py
# string_utils.py
# In string_utils.py:
# def uppercase(text):
# return text.upper()
# Import and use
from utils.string_utils import uppercase
text = input()
result = uppercase(text)
print(result)

Exercise 2: Package Import Methods

Given a package math_ops with module basic.py containing add(a, b), demonstrate three different ways to import and use this function. Use method 3 (direct function import) and calculate add(10, 20).

Package Import Methods

Checks: 0 times
Answer:
# Method 1: import package
# import math_ops
# result = math_ops.basic.add(10, 20)
# Method 2: import module
# from math_ops import basic
# result = basic.add(10, 20)
# Method 3: import function (using this)
from math_ops.basic import add
result = add(10, 20)
print(result)

Course Progress

Section 58 of 61

Back to Course