简体   繁体   中英

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 (ie 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 :)

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.

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.

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.

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.

An import statement loads the whole module in memory so that's why the test() function ran successfully.

But as you used from statement that's why you can't use the countLines and countChars directly but test can surely call them.

from statement basically loads the whole module and sets the imported function, variable etc to the global namespace.

for eg.

>>> from math import sin
>>> sin(90)               #now sin() is a global variable in the module and can be accesed directly
0.89399666360055785
>>> math
Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    math
NameError: name 'math' is not defined
>>> vars()  #shows the current namespace, and there's sin() in it
{'__builtins__': <module '__builtin__' (built-in)>, '__file__': '/usr/bin/idle', '__package__': None, '__name__': '__main__', 'main': <function main at 0xb6ac702c>, 'sin': <built-in function sin>, '__doc__': None}

consider a simple file, file.py:

def f1():
   print 2+2

def f2():
   f1()

import only f2:

>>> from file import f2
>>> f2()
4

though I only imported f2() not f1() but it ran f1() succesfully it's because the module is loaded in memory but we can only access f2() , but f2() can access other parts of the module.

From A GUIDE TO PYTHON NAMESPACES ,

Even though modules have their own global namespaces, this doesn't mean that all names can be used from everywhere in the module. A scope refers to a region of a program from where a namespace can be accessed without a prefix. Scopes are important for the isolation they provide within a module. At any time there are a number of scopes in operation: the scope of the current function you're in, the scope of the module and then the scope of the Python builtins. This nesting of scopes means that one function can't access names inside another function.

Namespaces are also searched for names inside out. This means that if there is a certain name declared in the module's global namespace, you can reuse the name inside a function while being certain that any other function will get the global name. Of course, you can force the function to use the global name by prefixing the name with the 'global' keyword. But if you need to use this, then you might be better off using classes and objects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM