2

In short: in Python it is too easy to create multiple instances of the same module, each instance having its own set of global variables.

I need to add a check to the module to detect such multiple instantiation and raise an exception.

My problem is the same as this one: Module imported multiple times

This is the smallest directory structure to reproduce the problem:

/test/a/__init__.py

/test/a/aa.py:
print "aa: __name__: ", __name__

/test/b/b.py:
from a import aa
import aa

Then

export PYTHONPATH=/test:/test/a
python /test/b/b.py

prints:

aa: __name__:  a.aa
aa: __name__:  aa

So, module aa.py was imported twice with different names.

Needless to say that module aa.py will get 2 sets of global variables, which screws up all the logic inside this module.

Of course, in the trivial example above it is easy to detect error by eyes, but in complex project with multiple subdirectories, these errors keep popping up regularly.

So, I need some really global variable or a process-wide store or something like that. Any idea?

Edit: Bibhas asked for an example of multiple instances of the same global variable. Here it is:

/test/a/__init__.py

/test/a/aa.py:
print "aa: __name__: ", __name__

import thread
import time

test_var = __name__

def test():
    for i in range(0,5):
        print "aa thread: test_var: ", test_var
        time.sleep(1)

thread.start_new_thread( test, () )

/test/b/b.py:

print "b: __name__: ", __name__

from a import aa
import aa

import time
time.sleep(10)

Now running

export PYTHONPATH=/test:/test/a
python /test/b/b.py

prints:

aa: __name__:  a.aa
aa: __name__:  aa
aa thread: test_var:  aa
aa thread: test_var:  a.aa
aa thread: test_var:  aa
aa thread: test_var:  a.aa
...

So, it is clear that there are 2 instances of variable test_var. If I will try to implement a singleton in this module, there will be 2 instances of this singleton, etc.

Edit2: So, solution suggested by Guy L is something like:

/test/a/aa.py:
import os
if "aa.py" in os.environ:
    raise Exception("Duplicate instantiation of aa.py")
os.environ["aa.py"] = __name__

It seems to work OK (as long as I do not call import on multiple threads). Anybody have a better one?

Community
  • 1
  • 1
jhnlmn
  • 381
  • 3
  • 11
  • `aa.py will get 2 sets of global variables`. Can you give an example of this? From what I see Python reads aa.py twice, hence executed the print statement twice, b.py still got just one global variable `aa`. `__name__` just shows the module name while being imported. It might as well be `__main__` depending on how you execute it. – Bibhas Debnath May 10 '13 at 06:08
  • Maybe to use def setV(x): global v, v =x and getV(): global v, return v. I'm pretty sure it will not work since the module is imported twice – Guy L May 10 '13 at 07:10

2 Answers2

2

It's an ugly workaround but you can use os.environ[] to set enviorment variables. I don't like it that much since it contaminates the eviroment variables.

Here is how you can set those: http://code.activestate.com/recipes/159462-how-to-set-environment-variables/

Good luck, Guy

Guy L
  • 2,824
  • 2
  • 27
  • 37
0

The problem is that you're making the module available from two different entries in your path.

That's something that shouldn't happen, you should have your entire project dir in the path, and all module imports done regardless of location inside the project use the full path for importing, so, instead of your example, it should be:

export PYTHONPATH=/test
python /test/b/b.py

And you'll always need to use the imports like on the first line of b.py:

from a import aa