6

I recently ran into some unusual behavior.

foo.py

a = 0
def bar():
    print (a)

Console:

>>> import foo
>>> foo.bar()
0
>>> foo.a = 10
>>> foo.bar()
10

Console:

>>> from foo import *
>>> bar()
0
>>> a
0
>>> a = 10
>>> a
10
>>> bar()
0

I'm inferring that import * is actually creating two copies of a - one in the global namespace and one inside the foo module which cannot be accessed. Is this behavior explained/documented anywhere? I'm having trouble figuring out what to search for.

This seems like a notable and unexpected consequence of import * but for some reason I've never seen it brought up before.

MattDMo
  • 100,794
  • 21
  • 241
  • 231
user65
  • 1,223
  • 1
  • 9
  • 12
  • 3
    This is a well defined behaviour, there's no hidden namespace, it's just that each function has knowledge about its module's globals. Globals in the current module won't affect the globals of an imported module. [*Each module has its own private symbol table, which is used as the global symbol table by all functions defined in the module. Thus, the author of a module can use global variables in the module without worrying about accidental clashes with a user’s global variables.*](https://docs.python.org/3/tutorial/modules.html#more-on-modules) – Ashwini Chaudhary Nov 24 '15 at 21:43
  • There's essentially no such thing as a user-defined global in Python. There's a nasty hack to create true globals, which you should essentially never use, but anything you just define like `a = 10` is at most module-level. – user2357112 Nov 24 '15 at 21:44
  • The original `a` from `foo` is part of that function's closure – jonrsharpe Nov 24 '15 at 21:44
  • I explain it here from a similar question : http://stackoverflow.com/a/33436302/902399 – A.H Nov 24 '15 at 21:45
  • So essentially import * executes the module as normal, then copies all its globals into the current namespace? – user65 Nov 24 '15 at 21:48
  • @user65 yes, which is why `import *` is generally considered a bad idea. – MattDMo Nov 24 '15 at 21:50
  • 2
    @user65 Exactly, but that doesn't mean if you override `a` in the current module the output of `bar` will also change. `bar()` will still get `a`'s value from `bar.__globals__`. – Ashwini Chaudhary Nov 24 '15 at 21:50
  • 1
    Thanks, I have a much better understanding of how scope and importing works in Python now. – user65 Nov 24 '15 at 21:51

1 Answers1

1

There is no such thing as a hidden namespace in Python and the described behaviour is the normal and expected one.

You should read https://docs.python.org/3/tutorial/modules.html#more-on-modules in order to understand better how the globals do do work.

sorin
  • 161,544
  • 178
  • 535
  • 806