NeuroAgent

Complete Guide to __all__ in Python Modules and Packages

Learn how Python's __all__ attribute controls module exports and package APIs. Discover best practices for using __all__ in __init__.py files to create clean, maintainable Python packages. Start mastering Python module organization today!

Question

What does the __all__ attribute mean in Python, and how is it used in __init__.py files?

NeuroAgent

The __all__ attribute in Python is a special list that defines which names should be exported when a module is imported using wildcard syntax (from module import *). In __init__.py files, it controls which modules and functions are considered part of a package’s public API when users perform wildcard imports from the package.

Contents


What is the __all__ Attribute?

The __all__ attribute is a special list in Python modules that defines the public API of that module. When a user executes from module import *, only the names listed in __all__ are imported into the current namespace. If __all__ is not defined, all names that do not start with an underscore (_) are imported instead.

python
# In a module called mymodule.py
__all__ = ['public_function', 'PublicClass']

def public_function():
    return "This is public"

def _private_function():
    return "This is private"

class PublicClass:
    pass

class _PrivateClass:
    pass

In this example, when someone imports using from mymodule import *, only public_function and PublicClass will be available. The private functions and classes (those starting with underscore) are excluded.


How __all__ Works in Modules

The __all__ attribute follows specific rules:

  1. Definition: It must be defined at the module level as a list or tuple of strings
  2. Content: Each string must correspond to a valid name defined in the module
  3. Scope: It only affects wildcard imports (from module import *)
  4. Fallback: When __all__ is not defined, all names without leading underscores are imported

Here’s how it works in practice:

python
# Without __all__
def visible_function():
    pass

def _invisible_function():
    pass

# from module import * would import visible_function but not _invisible_function

# With __all__
__all__ = ['visible_function']

def visible_function():
    pass

def _invisible_function():
    pass

# from module import * would only import visible_function

It’s important to note that __all__ doesn’t affect regular imports like import module or specific imports like from module import specific_name. These import methods work regardless of the __all__ definition.


Usage in __init__.py Files

In __init__.py files, the __all__ attribute serves a crucial role in package structure. __init__.py files can be empty or contain code that initializes the package. When __all__ is defined in an __init__.py file, it determines which modules and subpackages are considered part of the package’s public API.

Here’s a typical example:

mypackage/
├── __init__.py
├── module1.py
├── module2.py
└── subpackage/
    ├── __init__.py
    └── module3.py
python
# mypackage/__init__.py
__all__ = ['module1', 'module2']

# This makes module1 and module2 available via:
# from mypackage import *

This structure allows users to import from the package using a clean interface:

python
# Instead of:
from mypackage.module1 import function1
from mypackage.module2 import function2

# Users can do:
from mypackage import function1, function2

The __init__.py file can also be used to re-export functions and classes from submodules:

python
# mypackage/__init__.py
from .module1 import function1, function2
from .module2 import Class1
from .subpackage.module3 import function3

__all__ = ['function1', 'function2', 'Class1', 'function3']

This pattern creates a unified API where users don’t need to know the internal structure of the package.


Best Practices and Examples

When working with __all__, consider these best practices:

  1. Explicit is better than implicit: Always define __all__ to clearly specify the public API
  2. Keep it up to date: Ensure __all__ contains all public names and doesn’t reference undefined names
  3. Include docstrings: Document each item in __all__ to help understand the API
  4. Consider versioning: Use __all__ to manage API changes between versions

Here’s an example of a well-structured __all__:

python
"""A comprehensive example of __all__ usage."""

__all__ = [
    'public_function',
    'PublicClass',
    'CONSTANT',
    'submodule',
]

def public_function():
    """A public function accessible via import *."""
    return "public"

class PublicClass:
    """A public class accessible via import *."""
    pass

_CONSTANT = 42  # Private constant

import .submodule as submodule

Common Mistakes and Pitfalls

Several common issues arise when working with __all__:

  1. Undefined names: Referencing names in __all__ that aren’t defined in the module
  2. Missing names: Forgetting to include new public names in __all__
  3. Incorrect ordering: Not maintaining logical order in the __all__ list
  4. Over-reliance: Using __all__ as security (it’s not - it’s just a convention)

Example of a mistake:

python
# Incorrect: 'new_function' is not defined in this module
__all__ = ['public_function', 'new_function']

def public_function():
    pass

This will cause AttributeError when someone tries to import using from module import *.


Advanced Scenarios

In more complex scenarios, __all__ can be used dynamically:

python
# Dynamic __all__ based on available features
try:
    import expensive_module
    __all__ = ['basic_function', 'expensive_function']
except ImportError:
    __all__ = ['basic_function']

def basic_function():
    """Always available."""
    pass

def expensive_function():
    """Only available if expensive_module is installed."""
    return expensive_module.do_something()

Another advanced pattern is conditional exports:

python
# Conditional exports based on platform
import sys

if sys.platform == 'win32':
    __all__ = ['windows_function']
else:
    __all__ = ['unix_function']

def windows_function():
    """Windows-specific function."""
    pass

def unix_function():
    """Unix-specific function."""
    pass

Sources

  1. Python Language Reference - The import system
  2. Python Tutorial - Modules
  3. Python Documentation - Special module attributes
  4. PEP 8 - Style Guide for Python Code

Conclusion

The __all__ attribute is a powerful tool for managing Python module and package APIs. By explicitly defining which names should be exported, developers can create cleaner, more maintainable code interfaces. In __init__.py files, it serves as the package’s public contract, making it easier for users to work with complex packages without needing to understand their internal structure.

Key takeaways:

  • Always define __all__ to make your module’s API explicit
  • In __init__.py, use __all__ to create a unified package interface
  • Keep __all__ synchronized with your actual public API
  • Remember that __all__ only affects wildcard imports
  • Use descriptive naming and maintain logical order in your __all__ lists

By following these practices, you’ll create more professional, user-friendly Python packages that are easier to understand and maintain.