Alex Lin Wang 王帅

__all__

January 5, 2025 • 4 min read
Explicitly control what gets exported from your Python modules with __all__. Learn how to create cleaner public APIs and protect against unintended imports.

Imagine you're building an API where you have code for both private and public consumption. For example, you have a public function that has private helper functions.

def public_function(...) -> ...:
    ...
    private_function(...)
    ...

def private_function(...) -> ...:
    ...

In general, the pythonic way of resolving this is to preface with the protected prefix _ to indicate internal consumption.

def _private_function(...) -> ...:
    ...

Clear signaling of what functions are for/not for public consumption is helpful for maintaining and calling public APIs. However, on the flip side, everything without _ is assumed to be public implicitly. This could allow the import of non-public methods when using from module import *. This is error prone.

The Solution: __all__

Another way to achieve this same effect is to explicitly signal with the __all__ module attribute (although it looks like a dunder method, it isn't!).

def public_func():
    pass

def _private_func_mislabeled():
    pass

def _another_func1():
    pass

def another_func():
    pass

__all__ = ['public_func', '_private_func_mislabeled']  # explicit control

# from mymodule import * will import: public_func, _private_func_mislabeled
# another_func is excluded even though it's "public" by naming
# _another_func1 is also excluded, as it should be.

This limits the blast radius of any changes to non-public functions, as they won't be imported via import *. For example, if you wanted _another_func1 to be async, you could change it without worrying about breaking external code that might have accidentally imported it.

Key Benefits

  • Explicit API control: You decide exactly what's part of your public API
  • Protection from accidental exports: Functions without underscore prefixes won't be accidentally exported
  • Clear documentation: __all__ serves as a single source of truth for your module's public interface
  • Safer refactoring: Internal functions can be changed without worrying about breaking external code
  • IDE support: Many IDEs use __all__ to provide better autocomplete suggestions

Questions or feedback? Feel free to reach out!