If you think through what these commands actually do, it's pretty simple.
a.py:
import b
foo = 0
b.py:
bar = 1
c.py:
import a
From c
, you can't just say foo
, you have to say a.foo
. The same is true for every name in a
—constants, variables, functions, classes, and even modules. And that includes b
.
So, you can't say bar
or a.bar
, but you can say a.b.bar
.
Now, what if you change it like this:
a.py:
from b import *
foo = 0
b.py:
bar = 1
c.py:
from a import *
What that from b import *
does is take everything in b
's namespace, and puts it into a
's namespace, so you can directly say bar
from within a
. And then, when you do from a import *
, that takes everything in a
's namespace, and puts it into c
's, so just as you can do foo
, you can also do bar
.
This is why you usually don't want to do from b import *
anywhere except in your top-level script—because your namespaces get all merged together.
It's also why you can restrict what gets picked up by *
with __all__
:
a.py:
from b import *
__all__ = ['foo']
foo = 0
b.py:
bar = 1
c.py:
from a import *
Now, from c
, you can do c.foo
, but not c.bar
.
So, a
can do from b import *
to implement its own features, without exposing all of b
's internals to its users.