views:

53

answers:

1

I used to think that once a module was loaded, no re-importing would be done if other files imported that same module, or if it were imported in different ways. For example, I have mdir/__init__.py, which is empty, and mdir/mymod.py, which is:

thenum = None
def setNum(n):
    global thenum
    if thenum is not None:
        raise ValueError("Num already set")
    thenum = n

def getNum():
    if thenum is None:
        raise ValueError("Num hasn't been set")
    return thenum

First few use cases from the same file go according to expectation. This file is ./usage.py, the same folder mdir is in:

import mdir.mymod

mdir.mymod.setNum(4)
print mdir.mymod.getNum()

from mdir import mymod
print mymod.getNum()

from mdir.mymod import *
print getNum()
try:
    setNum(10)
except ValueError:
    print "YHep, exception"

The output is as expected:

4
4
4
YHep, exception

However, if I muck with the system path, then it looks like the module is imported anew:

#BEHOLD
import sys
sys.path.append("mdir")
import mymod
try:
    mymod.getNum()
except ValueError:
    print "Should not have gotten exception"

mymod.setNum(10)
print mymod.getNum()
print mdir.mymod.getNum()

That code, running after the previous code, yields:

Should not have gotten exception
10
4

What gives?

+4  A: 

mymod and mdir.mymod are considered different modules - here's somewhat related discussion: http://code.djangoproject.com/ticket/3951

Explanation:

It's best to play with python interactive interpreter and see for yourself. I created directory (package) mydir under some directory and inside it two files (modules) - __init__.py and mymod.py, both empty. I started python inside of directory containing mydir. Now see what happens:

>>> import mydir.mymod
>>> from mydir import mymod
>>> mymod == mydir.mymod
True

Why are mymod and mydir.mymod considered the same thing? Well, both names refer to the same module object - modules equality is determined by their paths comparison:

>>> mymod
<module 'mydir.mymod' from 'mydir\mymod.py'>
>>> mydir.mymod
<module 'mydir.mymod' from 'mydir\mymod.py'>

Now, if I alter sys.path to contain mydir and import mymod in such a way that path of imported module will seem to be different:

>>> import sys
>>> sys.path.append( "d:/zrodla/stack/mydir" )
# note that importing mymod (and not mydir.mymod) prior to appending mydir to 
# path would cause an error
>>> mymod2
<module 'mymod' from 'd:/zrodla/stack/mydir\mymod.pyc'>
>>> mymod2 == mydir.mymod
False

then resulting module objects will not compare equal. This way one module will be imported twice - it's normal and that's the way python works. Just remember that imported modules are identified by their paths - more specifically by 'dotted paths' I think - look at sys.modules keys:

>>> [x for x in sys.modules.keys() if "my" in x]
['mydir', 'mymod', 'mydir.mymod']

I hope it's clear now.

cji
but before the latest set of imports, `mdir.mymod` seemed to be the same module.
Claudiu
@Claudiu sorry for the wait, I added an explanation, hope it helps.
cji