Python tutorials > Modules and Packages > Packages > What is `__all__` in packages?

What is `__all__` in packages?

The __all__ variable in a Python package or module is a list of strings defining the public interface of that module or package. It's used to control what names are imported when a user imports the module or package using from package import * or from module import *. It essentially acts as an explicit allow list, preventing accidental exposure of internal functions and variables.

Basic Example of `__all__` in a Module

In this example, my_module.py defines two functions: public_function and _private_function. The __all__ list only includes 'public_function'. When a user does from my_module import *, only public_function will be imported.

# my_module.py

def public_function():
    return "This is a public function"

def _private_function():
    return "This is a private function"

__all__ = ['public_function']

Importing with `__all__`

This code demonstrates how __all__ affects imports. Attempting to use _private_function directly after from my_module import * will result in a NameError because it was not included in the __all__ list in my_module.py.

# main.py
from my_module import *

print(public_function())

# This will raise an error because _private_function is not imported
# print(_private_function())

Example in a Package

In a package, the __init__.py file often contains the __all__ variable. This controls which submodules or names within those submodules are exposed when the package itself is imported. Here, we import specific functions from module1 and module2 and make them part of the package's public interface through __all__.

# my_package/__init__.py

from .module1 import public_function1
from .module2 import public_function2

__all__ = ['public_function1', 'public_function2']

Concepts Behind the Snippet

The main concept behind __all__ is explicit control over the public API of your modules and packages. This helps in:

  1. Preventing namespace pollution: Avoid accidentally importing internal functions that should not be accessed directly.
  2. Abstraction: Hide implementation details and present a clean, well-defined interface to users.
  3. Refactoring: Modifying internal code without breaking external clients that rely only on the public API.

Real-Life Use Case Section

Consider a scientific library. The library might contain numerous internal helper functions and classes. Using __all__, the library developers can carefully expose only the core functions and classes that are intended for users, making the library easier to understand and use. This also allows the developers to change internal implementations without impacting external users who are only using the documented public API.

Best Practices

  • Always use `__all__`: Explicitly define your public API, even if it seems obvious.
  • Update `__all__` when refactoring: Ensure that changes to your code don't inadvertently expose internal details.
  • Document the public API: Clearly document the items listed in __all__ so that users understand how to use your module or package.
  • Avoid `from module import *` in production code: Although __all__ helps control the import, it's generally better to use explicit imports for clarity.

Interview Tip

When discussing __all__ in an interview, emphasize its role in defining and maintaining a clean public API. Highlight its importance for code maintainability, preventing namespace pollution, and enabling refactoring without breaking external code. Mention that explicit imports are generally preferred over from module import *, even with __all__ defined.

When to Use Them

Use __all__ in the following situations:

  • Public Libraries: Whenever you're developing a library that will be used by others.
  • Large Projects: In large projects with many modules to maintain a clean separation between internal and external code.
  • API Design: When you want to carefully design and control the public interface of your code.

Memory Footprint

__all__ itself has a very small memory footprint. It is simply a list of strings, and the memory used to store the list is generally negligible. The real memory impact comes from the objects that are made available to the user. Properly using __all__ can indirectly help improve memory efficiency by preventing the unnecessary loading of modules or definitions that are not intended for public use. This is because only the items in __all__ are imported when using the wildcard import.

Alternatives

While __all__ is the standard way to control wildcard imports, an alternative is to rely solely on explicit imports in your code. This means avoiding from module import * altogether and always specifying the exact names you want to import. While more verbose, explicit imports provide better clarity and avoid the potential pitfalls of wildcard imports, even with __all__ defined.

Pros

  • Explicit API: Clearly defines the public interface of a module or package.
  • Namespace Control: Prevents unintended import of internal functions and variables.
  • Code Maintainability: Facilitates refactoring without breaking external code.

Cons

  • Maintenance Overhead: Requires updating the __all__ list whenever the public API changes.
  • Potential for Errors: Forgetting to include a public function in __all__ will make it inaccessible via wildcard imports.

FAQ

  • What happens if `__all__` is not defined?

    If __all__ is not defined in a module or package, from module import * will import all names that do not begin with an underscore (_). However, relying on this implicit behavior is generally discouraged. Defining __all__ explicitly makes your intentions clear and provides better control over the public API.

  • Can `__all__` contain names that are not defined in the current module?

    Yes, __all__ can contain names that are defined in other modules but are re-exported in the current module. This is common in package __init__.py files where you want to aggregate functions from different submodules into a single, convenient interface.

  • Does `__all__` affect explicit imports?

    No, __all__ only affects wildcard imports (from module import *). Explicit imports, such as import module or from module import specific_name, will always import the specified names regardless of what is in __all__.