Multiple import of the same module under different names

George Sakkis george.sakkis at gmail.com
Thu Mar 11 11:21:51 CET 2010


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 ?

George


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

~/pkg/
   __init__.py  # empty
   mod1.py
   mod2.py
   mod3.py
   mod4.py
   main.py
   subpkg/
      __init__.py  # empty
      foo.py # empty

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

~$ PYTHONPATH=. python pkg/main.py

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

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

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

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

### mod1.py ###
# implicit relative import
from subpkg import foo

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

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

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

### main.py ###
#!/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

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



More information about the Python-list mailing list