Stop Guessing What Gets Imported: Python's `__all__` Attribute
Learn how Python's `__all__` attribute controls what gets imported with `from module import *`, why it's essential for clean APIs, and when to use or skip it in your projects.
You've probably seen it in open-source projects or your colleague's code—that mysterious __all__ list at the top of a module. It looks harmless, but it has a big job.
Let's cut through the noise. __all__ is Python's way of controlling what happens when someone writes from module import *. Without it, Python imports everything that doesn't start with an underscore. With it, you decide exactly what's public.
Why __all__ Actually Matters
Imagine you're building a utility module for PythonSkillset's analytics toolkit. You have helper functions for internal calculations, logging setup, and maybe a few things you're experimenting with. The last thing you want is for someone who types from analytics import * to suddenly have their namespace cluttered with your _clean_data and __temp_cache functions.
Here's the problem: many developers never run from module import *. But libraries do. Third-party code does. And when they do, __all__ is your defense.
How It Works in Practice
# utils.py
__all__ = ['parse_data', 'validate_input']
def parse_data(raw):
# ... processing logic
return cleaned
def validate_input(data):
# ... validation logic
return True
def _internal_helper():
# This won't be imported with *
pass
def __debug_mode():
# Neither will this
pass
When someone does from utils import *, they only get parse_data and validate_input. The other two functions? Hidden.
What Happens Without __all__
Python falls back to its default behavior: it imports everything that doesn't start with an underscore. Single underscore _helper? Gone. Dunder __magic? Also gone. But anything without an underscore—even functions you consider internal—gets pulled in.
This is where __all__ becomes your explicit contract. You're saying: "These are the functions users should care about. The rest is implementation detail."
A Real-World Example
At PythonSkillset, we once had a module with 20 helper functions, only 5 of which were meant for public use. Without __all__, new team members would accidentally from our_module import * and end up with a namespace full of utility functions they'd never need. Adding __all__ was a five-minute fix that saved hours of confusion.
When You Should Use It
- Library code – If you're publishing a package,
__all__is non-negotiable. - Team projects – It communicates intent clearly.
- Any module with many internals – Keep your public API clean.
When You Can Skip It
- Small scripts you'll never reuse
- Modules with only a few functions that are all public
- When your code is only imported by
import module(notfrom module import *)
One Tricky Detail
__all__ only affects from module import *. It has no effect on:
- import module (you still get the whole module object)
- Explicit imports like from module import _internal_func
- import module as mod
This catches people off guard. If you're trying to hide something completely, __all__ isn't your tool. Use single underscores for that.
Final Thought
__all__ isn't about security. It's not a lock. It's a sign. It tells other developers: "Start here. These are the tools I designed for you."
Next time you write a module, ask yourself: if someone does import *, what would they actually want? That's your __all__.
Comments
Questions, corrections, and tips stay visible for everyone reading this page.
Join the discussion
No comments yet
Be the first to leave a note — it helps the next reader.