1

this is something that I can't quite figure out in pythion's imports. Let's say I have a module 'a' that imports module 'b' with 'import b' Then, there is a module 'c' that imports module 'a'. Will the names form the module 'b' be available in 'c'?

I've checked that it actually depends on how you import the module 'a' in module 'c'. If you do 'import a' then names from 'b' will not be available in 'c'. However, if you do 'from a import *' then they will be available. Can someone pls clarify the difference?

spoonboy
  • 2,570
  • 5
  • 32
  • 56

3 Answers3

4

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.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • +1 because I didn't know about `__all__`. – Kyle Strand Jan 10 '13 at 22:24
  • "So, you can't say bar or a.bar, but you can say a.b.bar" I'm getting 'Object a has no attribute b' when trying this. – spoonboy Jan 10 '13 at 22:27
  • @spoonboy: Yes, I can say `a.b.bar`, I just can't say it 10 times fast. (Even though I just realized it's pretty close to the start of my own username…) – abarnert Jan 10 '13 at 22:28
  • Ok, this works. Could you pls clarify why it doesn't work when I import module b with 'from b import *' ? (but use 'import a' in 'c') – spoonboy Jan 10 '13 at 23:01
  • As well, by some reason it doesn't work with full path names. I.e. let's say all the three modules belong to the same package 'p'. The imports would be 'import p.b' in 'a' and 'import p.a' in c. When I try p.b.p.a.bar in 'c'it produces an error. – spoonboy Jan 10 '13 at 23:06
  • I'm not sure what your first followup question means. When `a` has `from b import *`, and `c` has `import a`, `c` can do `a.bar` just as it can do `a.foo`. Is that not what you're looking for? – abarnert Jan 10 '13 at 23:11
  • For your second question: You've done it backward. `c` imported `p.a`, not `p.b`, so you want `p.a.p.b.bar`. And that works fine. (This is all a whole lot easier if you do things from the interactive interpreter instead of from a script `c.py`, because then you can do things like `dir(p.a)` interactively.) – abarnert Jan 10 '13 at 23:15
  • Thanks, it works. I just did't put the package prefix when importing 'b' in module 'a'. – spoonboy Jan 10 '13 at 23:54
3

The import statement causes a module to be executed, with all variables being kept in the namespace of the module executed. That is to say, if you import a, then all of a's variables will be under a.[variable]. The from keyword gives slightly different behavior: it puts the variable in the current namespace. For instance, from a import foo puts the variable foo in the current namespace. from a import * imports all variables from a into the current namespace. The as keyword allows you to rename variables when you import them; thus from a import foo as bar allows you to access a.foo, but you must call it bar; import a.foo as foo is equivalent to from a import foo.

Kyle Strand
  • 15,941
  • 8
  • 72
  • 167
1

A more concrete example than above:

a.py

import b
bar = 'bar'

b.py

foo = 'foo'

c.py

import a


try:
   print(b.foo)
except:
   print('No `b` in current namespace')

try:
   print(a.bar)
except:
   print('No `a` in current namespace')

try:
   print(a.b.foo)
except:
   print('No `a` or `a.b` in current namespace')

This should print (in order):

No `b` in current namespace
bar
foo

In other words, b is available through a but only by accessing a's namespace

Ian Stapleton Cordasco
  • 26,944
  • 4
  • 67
  • 72