Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Some confusion regarding imports in Python

I'm new to Python and there's something that's been bothering me for quite some time. I read in "Learning Python" by Mark Lutz that when we use a from statement to import a name present in a module, it first imports the module, then assigns a new name to it (i.e. the name of the function, class, etc. present in the imported module) and then deletes the module object with the del statement. However what happens if I try to import a name using from that references a name in the imported module that itself is not imported? Consider the following example in which there are two modules mod1.py and mod2.py:

#mod1.py
from mod2 import test
test('mod1.py')        

#mod2.py
def countLines(name):
    print len(open(name).readlines())

def countChars(name):
    print len(open(name).read())

def test(name):
    print 'loading...'
    countLines(name)
    countChars(name)
    print '-'*10

Now see what happens when I run or import mod1:

>>>import mod1

loading...
3
44
----------

Here when I imported and ran the test function, it ran successfully although I didn't even import countChars or countLines, and the from statement had already deleted the mod2 module object.

So I basically need to know why this code works even though considering the problems I mentioned it shouldn't.

EDIT: Thanx alot to everyone who answered :)

like image 747
IsolatoR Avatar asked Aug 14 '12 18:08

IsolatoR


4 Answers

Every function have a __globals__ attribute which holds a reference for the environment where it search for global variables and functions.

The test function is then linked to the global variables of mod2. So when it calls countLines the interpreter will always find the right function even if you wrote a new one with the same name in the module importing the function.

like image 146
JBernardo Avatar answered Oct 21 '22 02:10

JBernardo


I think you're wrestling with the way python handles namespaces. when you type from module import thing you are bringing thing from module into your current namespace. So, in your example, when mod1 gets imported, the code is evaluated in the following order:

from mod2 import test #Import mod2, bring test function into current module namespace
test("mod1.py")  #run the test function (defined in mod2)

And now for mod2:

#create a new function named 'test' in the current (mod2) namespace 
#the first time this module is imported.  Note that this function has
#access to the entire namespace where it is defined (mod2).
def test(name):  
    print 'loading...'
    countLines(name)
    countChars(name)
    print '-'*10

The reason that all of this is important is because python lets you choose exactly what you want to pull into your namespace. For example, say you have a module1 which defines function cool_func. Now you are writing another module (module2) and it makes since for module2 to have a function cool_func also. Python allows you to keep those separate. In module3 you could do:

import module1
import module2
module1.cool_func()
module2.cool_func()

Or, you could do:

from module1 import cool_func
import module2 
cool_func() #module1
module2.cool_func()

or you could do:

from module1 import cool_func as cool
from module2 import cool_func as cooler
cool()  #module1
cooler() #module2

The possibilities go on ...

Hopefully my point is clear. When you import an object from a module, you are choosing how you want to reference that object in your current namespace.

like image 31
mgilson Avatar answered Oct 21 '22 02:10

mgilson


The other answers are better articulated than this one, but if you run the following you can see that countChars and countLines are actually both defined in test.__globals__:

from pprint import pprint
from mod2 import test

pprint(test.__globals___)
test('mod1')

You can see that importing test brings along the other globals defined in mod2, letting you run the function without worrying about having to import everything you need.

like image 26
RocketDonkey Avatar answered Oct 21 '22 01:10

RocketDonkey


Each module has its own scope. Within mod1, you cannot use the names countLines or countChars (or mod2).

mod2 itself isn't affected in the least by how it happens to be imported elsewhere; all names defined in it are available within the module.

If the webpage you reference really says that the module object is deleted with the del statement, it's wrong. del only removes names, it doesn't delete objects.

like image 29
Wooble Avatar answered Oct 21 '22 03:10

Wooble