Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is behavior different with respect to global variables in "import module" vs "from module import * "?

Let's have a.py be:

def foo():
    global spam
    spam = 42
    return 'this'

At a console, if I simply import a, things make sense to me:

>>> import a
>>> a.foo()
'this'
>>> a.spam
42

However, if I do the less popular thing and...

>>> from a import *
>>> foo()
'this'
>>> spam
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'spam' is not defined
>>> a.spam
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined

I've read opinions about why people don't like "from module import * " from a namespace perspective, but I can't find anything on this behavior, and frankly I figured out that this was the issue I was having by accident.

like image 923
User 4574 Avatar asked Nov 13 '15 07:11

User 4574


3 Answers

When you ask for a.spam there happens a namespace search in the module a and spam is found. But when you ask for just spam:

>>> from a import *  # imported foo, spam doesn't exist yet
>>> foo()

spam is created in the namespace a (you cannot access it with such import though), but not in the current module. And it seems like nobody promised us to add newly added globals of a to all the namespaces module a has been imported into via *. That will require storing import links inside the interpreter and probably will degrade performance if one heavily imported module does such tricks all the time.

And imagine you have defined spam in your main module prior to calling foo(). That would be downright name collision.

Just as illustration, you can do from a import * to get fresh updates for the module a:

from a import *
print(foo())
from a import *
print(spam)
like image 136
u354356007 Avatar answered Sep 23 '22 12:09

u354356007


Let's go thorough it step by step:

At the point of importing, a only has the symbol foo which refers to a function.

Only if the function is executed, a gets the additional symbol spam.

In the first case, you do import a and get a "handle" to the module, which allows you to monitor whatever happens later. If you'd do a.spam before calling a.foo(), you'd get an error.

In the second case, from a import * gives you whatever currently is in the module - and that's just spam(). After calling that, you could do from a import * to get spam as well.

like image 38
glglgl Avatar answered Sep 20 '22 12:09

glglgl


I generally agree with Vovanrock2002.

As was recently explained to me, the '.' is a scope resolution operator. import a and from a import * give you different syntaxes. from a import * imports each global variable from a separately, and binds them as variables in the local scope. A more practical example might be the difference between import datetime and from datetime import date. With the former, I have to create a date object using datetime.date(2015, 11, 12), with the latter I get to just use date(2015, 11, 12).

You can read more on the import statement

I would have to differ with you, however, in that I don't believe that spam is the meaning of life, the universe, and everything.

like image 41
NotAnAmbiTurner Avatar answered Sep 22 '22 12:09

NotAnAmbiTurner