python – `from … import` vs `import .`

python – `from … import` vs `import .`

It depends on how you want to access the import when you refer to it.

from urllib import request
# access request directly.
mine = request()

import urllib.request
# used as urllib.request
mine = urllib.request()

You can also alias things yourself when you import for simplicity or to avoid masking built ins:

from os import open as open_
# lets you use os.open without destroying the 
# built in open() which returns file handles.

Many people have already explained about import vs from, so I want to try to explain a bit more under the hood, where the actual difference lies.

First of all, let me explain exactly what the basic import statements do.

import X

Imports the module X, and creates a reference to that module in the
current namespace. Then you need to define completed module path to
access a particular attribute or method from inside the module (e.g.:
X.name or X.attribute)

from X import *

Imports the module X, and creates references to all public objects
defined by that module in the current namespace (that is, everything
that doesn’t have a name starting with _) or whatever name
you mentioned.

Or, in other words, after youve run this statement, you can simply
use a plain (unqualified) name to refer to things defined in module X.
But X itself is not defined, so X.name doesnt work. And if name
was already defined, it is replaced by the new version. And if name in X is
changed to point to some other object, your module won’t notice.

This makes all names from the module available in the local namespace.

Now lets see what happens when we do import X.Y:

>>> import sys
>>> import os.path

Check sys.modules with name os and os.path:

>>> sys.modules[os]
<module os from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc>
>>> sys.modules[os.path]
<module posixpath from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc>

Check globals() and locals() namespace dict with name os and os.path:

 >>> globals()[os]
<module os from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc>
>>> locals()[os]
<module os from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc>
>>> globals()[os.path]
Traceback (most recent call last):
  File <stdin>, line 1, in <module>
KeyError: os.path
>>>    

From the above example, we found that only os is added to the local and global namespaces.
So, we should be able to use os:

 >>> os
 <module os from     
  /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc>
 >>> os.path
 <module posixpath from      
 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc>
 >>>

…but not path:

>>> path
Traceback (most recent call last):
  File <stdin>, line 1, in <module>
NameError: name path is not defined 
>>>

Once you delete the os from locals() namespace, you wont be able to access either os or os.path, even though they do exist in sys.modules:

>>> del locals()[os]
>>> os
Traceback (most recent call last):
  File <stdin>, line 1, in <module>
NameError: name os is not defined
>>> os.path
Traceback (most recent call last):
  File <stdin>, line 1, in <module>
NameError: name os is not defined
>>>

Now lets look at from.

from

>>> import sys
>>> from os import path

Check sys.modules with name os and os.path:

>>> sys.modules[os]
<module os from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc>
>>> sys.modules[os.path]
<module posixpath from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc>

So sys.modules looks the same as it did when we imported using import name.

Okay. Lets check what it the locals() and globals() namespace dicts look like:

>>> globals()[path]
<module posixpath from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc>
>>> locals()[path]
<module posixpath from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc>
>>> globals()[os]
Traceback (most recent call last):
  File <stdin>, line 1, in <module>
KeyError: os
>>>

You can access by using path, but not by os.path:

>>> path
<module posixpath from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc>
>>> os.path
Traceback (most recent call last):
  File <stdin>, line 1, in <module>
NameError: name os is not defined
>>>
 

Lets delete path from locals():

>>> del locals()[path]
>>> path
Traceback (most recent call last):
  File <stdin>, line 1, in <module>
NameError: name path is not defined
>>>

One final example using aliasing:

>>> from os import path as HELL_BOY
>>> locals()[HELL_BOY]
<module posixpath from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc>
>>> globals()[HELL_BOY]
<module posixpath from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc>
>>>

And no path defined:

>>> globals()[path]
Traceback (most recent call last):
 File <stdin>, line 1, in <module>
KeyError: path
>>>

One pitfall about using from

When you import the same name from two different modules:

>>> import sys
>>> from os import stat
>>> locals()[stat]
<built-in function stat>
>>>
>>> stat
<built-in function stat>

Import stat from shutil again:

>>>
>>> from shutil import stat
>>> locals()[stat]
<module stat from 
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/stat.pyc>
>>> stat
<module stat from 
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/stat.pyc>
>>>

THE LAST IMPORT WILL WIN

python – `from … import` vs `import .`

There is a difference. In some cases, one of those will work and the other wont. Here is an example: say we have the following structure:

foo.py
mylib
    a.py
    b.py

Now, I want to import b.py into a.py. And I want to import a.py to foo. How do I do this? Two statements, in a I write:

import b

In foo.py I write:

import mylib.a

Well, this will generate an ImportError when trying to run foo.py. The interpreter will complain about the import statement in a.py (import b) saying there is no module b. So how can one fix this? In such a situation, changing the import statement in a to import mylib.b
will not work since a and b are both in mylib. The solution here (or at least one solution) is to use absolute import:

from mylib import b

Source: Python: importing a module that imports a module

Leave a Reply

Your email address will not be published. Required fields are marked *