Skip to main content

How to Check If a Module Is a Package in Python

In Python, the terms "module" and "package" are often used interchangeably, but they have distinct technical definitions. A module is typically a single file (.py), whereas a package is a directory containing an __init__.py file (and potentially other modules) that allows for a hierarchical structure.

Knowing whether an imported object is a package or a simple module is useful for introspection, dynamic importing, or traversing code structures. This guide explains how to distinguish between them using the __path__ attribute.

Understanding the Distinction

Before checking programmatically, it helps to visualize the structure.

  • Package: A container. It maps to a directory. It must have __path__ because Python needs to know where to look for submodules.
  • Module: A unit of code. It maps to a file. It does not have submodules, so it does not need a __path__.

Example Structure:

project/
main.py
my_package/ <-- This is a Package
__init__.py
my_module.py <-- This is a Module

Method 1: Checking the __path__ Attribute

The most definitive way to identify a package is to check for the existence of the __path__ attribute. Only packages have this attribute; standard modules do not.

Example of AttributeError

If you try to access __path__ on a standard module, Python raises an error.

import my_package.my_module

# ⛔️ Incorrect: Accessing __path__ on a simple module causes a crash
try:
print(my_package.my_module.__path__)
except AttributeError as e:
print(f"Error: {e}")

Output:

Error: module 'my_package.my_module' has no attribute '__path__'

The Safe Check using hasattr()

To safely determine if an imported object is a package, use hasattr().

import my_package
import my_package.my_module
import os

# ✅ Correct: Check for __path__ to identify packages
if hasattr(my_package, '__path__'):
print(f"'my_package' IS a package. Path: {my_package.__path__}")
else:
print("'my_package' is NOT a package.")

if hasattr(my_package.my_module, '__path__'):
print("'my_module' IS a package.")
else:
print("'my_module' is NOT a package (it is a module).")

# Even built-in modules follow this rule
if hasattr(os, '__path__'):
print("'os' IS a package.") # os is actually a package because it imports sys-dependent modules

Output:

'my_package' IS a package. Path: ['/path/to/project/my_package']
'my_module' is NOT a package (it is a module).
'os' is NOT a package. (Note: Output depends on implementation, usually os is a module wrapper)
note

The __path__ attribute is a list of strings representing the filesystem locations where Python looks for the package's submodules.

Method 2: Using inspect (Alternative)

While __path__ is the standard indicator, you can also use the inspect module to verify the file source. Packages usually point to an __init__.py file.

import inspect
import my_package
import my_package.my_module

def check_is_package(module):
# Get the file path
file_path = getattr(module, '__file__', '')

# Check if it is an __init__.py file
if file_path and '__init__.py' in file_path:
return True
return False

# ✅ Correct: Checking the file source
print(f"Is my_package a package? {check_is_package(my_package)}")
print(f"Is my_module a package? {check_is_package(my_package.my_module)}")

Output:

Is my_package a package? True
Is my_module a package? False
warning

The __file__ check is less robust than __path__. Namespace packages (introduced in Python 3.3) are packages that do not require an __init__.py file, so the file check method might fail for them. The hasattr(mod, '__path__') method works for namespace packages as well.

Conclusion

To distinguish between packages and modules in Python:

  1. Use hasattr(module, '__path__'). This is the most reliable and "Pythonic" method.
  2. If True, the module is a package (it handles submodules).
  3. If False, it is a standard module (a single file).