Multiple import of the same module under different names


George Sakkis

The import mechanism is not very smart in identifying whether two
modules imported under different name are actually the same module, at
least when dealing with implicit relative imports and sys.path
manipulation. However, at least in cases of plain file modules, the
module's __file__ would be adequate (or at least better than __name__)
in determining this. Below is an illustration of the different
situations (absolute imports, explicit relative imports, implicit
relative import, sys.path tweaking). So why does not import consult
__file__ before deciding to create a new module instance ?


=== File structure =============

~/pkg/ # empty
subpkg/ # empty # empty

=== Run =============

~$ PYTHONPATH=. python pkg/

=== Output =============

Imported foo from pkg.subpkg: <module '' from
Imported foo from subpkg: <module '' from
Imported foo from pkg.mod1: <module '' from
Imported foo from mod1: <module '' from
Imported foo from pkg.mod2: <module '' from
Failed to import foo from mod2: Attempted relative import in non-package
Imported foo from pkg.mod3: <module '' from
Imported foo from mod3: <module '' from
Imported foo from pkg.mod4: <module 'foo' from
Imported foo from mod4: <module 'foo' from '/home/george/pkg/subpkg/foo.pyc'>

* 9 total module(s)
* 3 distinct module(s)
<module '' from '/home/george/pkg/subpkg/foo.pyc'>
<module '' from '/home/george/pkg/subpkg/'>
<module 'foo' from '/home/george/pkg/subpkg/foo.pyc'>
* 1 distinct file(s)

=== Code =============

### ###
# implicit relative import
from subpkg import foo

### ###
# explicit relative import
from .subpkg import foo

### ###
# absolute import
from pkg.subpkg import foo

### ###
# absolute import after tweaking sys.path
import sys
from os.path import dirname,join
sys.path.append(join(dirname(__file__), 'subpkg'))
import foo

### ###
#!/usr/bin/env python

from os.path import abspath, normpath

def test(*modules):
module_set = set(modules)
file_set = set(module_file(m) for m in modules)
print '* %d total module(s)' % len(modules)
print '* %d distinct module(s)' % len(module_set)
for m in module_set:
print '\t', m
print '* %d distinct file(s)' % len(file_set)
for f in file_set:
print '\t', f

def module_file(mod):
f = abspath(normpath(mod.__file__))
if f.endswith('.pyc'):
f = f[:-1]
return f

if __name__ == '__main__':
from pkg.subpkg import foo
print 'Imported foo from pkg.subpkg:\t', foo
from subpkg import foo as rel_foo
print 'Imported foo from subpkg:\t\t', rel_foo

from pkg.mod1 import foo as foo1
print 'Imported foo from pkg.mod1:\t', foo1
from mod1 import foo as rel_foo1
print 'Imported foo from mod1:\t\t', rel_foo1

from pkg.mod2 import foo as foo2
print 'Imported foo from pkg.mod2:\t', foo2
try: from mod2 import foo as rel_foo2
except ValueError, ex:
print 'Failed to import foo from mod2:', ex

from pkg.mod3 import foo as foo3
print 'Imported foo from pkg.mod3:\t', foo3
from mod3 import foo as rel_foo3
print 'Imported foo from mod3:\t\t', rel_foo3

from pkg.mod4 import foo as foo4
print 'Imported foo from pkg.mod4:\t', foo4
from mod4 import foo as rel_foo4
print 'Imported foo from mod4:\t\t', rel_foo4

test(foo, rel_foo,
foo1, rel_foo1,
foo2, # rel_foo2,
foo3, rel_foo3,
foo4, rel_foo4)


Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question