jhnlmn
jhnlmn

Reputation: 401

How to detect or prevent multiple instances of the same modules in Python?

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?

Upvotes: 2

Views: 1641

Answers (2)

José Teixeira
José Teixeira

Reputation: 1

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

Upvotes: 0

Guy L
Guy L

Reputation: 2954

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

Upvotes: 2

Related Questions