Skip to main content
Python

What's the difference between a Python module, package, and namespace?

4 mins

Matryoshka, nesting dolls representing modules, packages, and namespaces

What are Python Modules, Packages, and Namespaces? #

Many developers new to Python are often confused by the terms module, package, and namespace. They are present in Python documentation, error messages, and discussions. Understanding these fundamental concepts helps when working with Python.

In brief:

  • A module is a single file containing Python code. It can define functions, classes, and variables. You can import a module to use its functionality in your code.

  • A package is a directory that contains multiple modules. It can also contain sub-packages. A package is a way to organize related modules together. You can import a package to access its modules.

  • A namespace is a way to organize and manage the names of variables, functions, and classes in Python. It helps prevent naming conflicts.

Modules #

A module is simply a file containing Python code

Your Python code is organized into files. Each file with a .py extension is a module. A module can contain functions, classes, and variables.

# my_module.py

def greet(name):
    return f"Hello, {name}!"

Importing a module loads its contents into your code, allowing you to use its functionality. For example, the math module provides mathematical functions like sqrt and sin.

import math

print(math.sqrt(16))

Packages #

Organize related modules together with packages

A package is a way to organize related modules together. It is a directory that contains multiple modules and can also contain sub-packages. It typically contains a special file called __init__.py to be recognized as a package.

Note that in Python 3.3 and later, the __init__.py file is not strictly required for a directory to be considered a package, but it is still commonly used to initialize the package and define its public API. See the article The __init__.py is still useful for more information.

Here is an example of a package structure and how to import from it:


# project/
# ├── app.py
# └── mypkg/
#     ├── __init__.py
#     └── greetings.py

# mypkg/__init__.py
# (empty)

# mypkg/greetings.py
def greet(name):
    return f"Hello, {name}!"

# app.py
from mypkg.greetings import greet
print(greet("Ada"))

# alternative import
# app.py
import mypkg.greetings as greetings
print(greetings.greet("Ada"))

Namespaces #

Avoid naming collisions with namespaces

A namespace is a way to organize and manage the names of variables, functions, and classes in Python. It helps prevent naming conflicts by providing a way to distinguish between different entities with the same name.

When you import a module or package, it creates a namespace for that module or package. This allows you to access its contents without worrying about name clashes with other modules or packages.

For example, if you have two modules that both define a function called greet, they are imported into different namespaces, so you can use both functions without conflict.

# module1.py
def greet(name):
    return f"Hello from module1, {name}!"
# module2.py
def greet(name):
    return f"Hello from module2, {name}!"

# app.py
import module1
import module2

print(module1.greet("Alice"))
print(module2.greet("Bob"))

Here, the greet functions from module1 and module2 are in different namespaces. The namespaces are:

  • module1.greet -> refers to the greet function in module1
  • module2.greet -> refers to the greet function in module2

Use globals() for clarification #

Using the globals() function, you can see the current global namespace, which includes all names defined at the top level of your code, including imported modules and packages.

This is useful when debugging or trying to understand which names are available in the current scope after importing modules and packages.

For example:

print(globals()) ## will show the default global namespace with built-in functions

from mypkg.greetings import greet
print(globals()) ## will now include 'greet' in the global namespace

import mypkg.greetings as greetings
print(globals()) ## will now include 'greetings' in the global namespace

import module1
import module2
print(globals()) ## will now include 'module1' and 'module2' in the global namespace

Common Pitfalls #

Name Collisions #

Naming your file the same as a standard library module can cause name collisions. For example, if you create a file named math.py in your project, it will shadow the built-in math module when you try to import it.

# math.py (your file)
def sqrt(x):
    return "This is not the real math.sqrt function!"  

# app.py
import math
print(math.sqrt(16))  # This will call your math.sqrt, not the built-in math.sqrt, leading to unexpected behavior.

Using from module import * #

Using from module import * can lead to name collisions and make it unclear where certain functions or variables are coming from. It is generally recommended to avoid this practice and instead use explicit imports.

# avoid this
from math import *

# better to do this
import math
print(math.sqrt(16))

# or this
from math import sqrt
print(sqrt(16))

Confusing namespace package with namespace #

A namespace package is a packaging/import feature that may have no __init__.py file, but it is still a package.

It is different from a namespace, which is a name-to-object mapping that helps avoid naming conflicts.