An often misunderstood piece of Python import machinery is the
While it is completely optional,
it’s common to see modules with the
__all__ list populated explicitly:
__all__ = ['Foo', 'bar'] class Foo(object): # ... def bar(): # ... def baz(): # ...
Before explaining what the real purpose of
(and how it relates to the titular wild imports),
let’s deconstruct some common misconceptions by highlighting what it isn’t:
__all__doesn’t prevent any of the module symbols (functions, classes, etc.) from being directly imported. In our the example, the seemingly omitted
bazfunction (which is not included in
__all__), is still perfectly importable by writing
from module import baz.
__all__doesn’t influence what symbols are included in the results of
vars(module). So in the case above, a
dircall would result in a
['Foo', 'bar', 'baz']list, even though
'baz'does not occur in
In other words, the content of
__all__ is more of a convention
rather than a strict limitation.
Regardless of what you put there, every symbol defined in your module
will still be accessible from the outside.
This is a clear reflection of the common policy in Python:
assume everyone is a consenting adult,
and that visibility controls are not necessary.
Without an explicit
Python simply puts all of the module “public” symbols there anyway1.
The meaning of it
So, what does
__all__ actually effect?
This is neatly summed up in this brief StackOverflow answer. Simply speaking, its purpose is twofold:
It tells the readers of the source code — be it humans or automated tools — what’s the conventional public API exposed by the module.
It lists names to import when performing the so-called wild import:
from module import *.
Because of the default content of
__all__ that I mentioned earlier,
the public API of a module can also be defined implicitly.
Some style guides (like the Google one)
are therefore relying on the
_private naming exclusively.
Nevertheless, an explicit
__all__ list is still a perfectly valid option,
especially considering that no approach offers any form of actual access control.
The second point, however, has some real runtime significance.
In Python, like in many other languages,
it is recommended to be explicit about the exact functions and classes we’re importing.
import statement will thus take one of the following forms:
import random import urllib.parse from random import randint from logging import fatal, warning as warn from urllib.parse import urlparse # etc.
In each case, it’s easy to see the relevant name being imported.
Regardless of the exact syntax and the possible presence of aliasing (
it’s always the last (qualified) name in the
before a newline or comma.
Contrast this with an
import that ends with an asterisk:
from itertools import *
Why? Because you cannot easily see what exact names are being imported here.
For that you’d have to go to the module’s source and — you guessed it —
look at the
Taming the wild
Barring some less important details,
the mechanics of
import * could therefore be expressed in the following Python (pseudo)code:
import module as __temp for __name in module: globals()[name] = getattr(__temp, __name) del __temp del __name
One interesting case to consider is
what happens when
__all__ contains a wrong name.
What if one of the strings there doesn’t correspond to any name within the module?…
# foo.py __all__ = ['Foo'] def bar(): pass >>> import foo >>> from foo import * Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'module' object has no attribute 'Foo'
import * blows up.
Notice, however, that regular import still works.
All in all (ahem), this hints at a cute little trick which is also very self-evident:
__all__ = ['DO_NOT_WILD_IMPORT']
Put this in a Python module, and no one will be able to
import * from it!
Much more effective than any lint warning ;-)
__all__ the things
Jokes aside, this phenomenon (
__all__ with an out-of-place name in it) can also backfire.
it’s relatively easy to introduce stray
one which doesn’t correspond to any
name that’s actually present in the namespace.
If we commit such a mishap, we are inadvertently lying about the public API of our package. What’s worse is that this mistake can propagate through documentation generators, and ultimately mislead our users.
While some linters may be able to catch this, a simple test like this one:
def test_all(self): """Test that __all__ contains only names that are actually exported.""" import yourpackage missing = set(n for n in yourpackage.__all__ if getattr(yourpackage, n, None) is None) self.assertEmpty( missing, msg="__all__ contains unresolved names: %s" % ( ", ".join(missing),))
is a quick & easy way to ensure this never happens.