Python

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.

July 2026 4 min read 10 views 0 hearts

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

  1. Library code – If you're publishing a package, __all__ is non-negotiable.
  2. Team projects – It communicates intent clearly.
  3. 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 (not from 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.

0 in thread

Join the discussion

Shown next to your comment.

Up to 4,000 characters

No comments yet

Be the first to leave a note — it helps the next reader.