tags:

views:

107

answers:

4

I am using the Borg pattern with mutual inclusion of modules. See the example code (not the real code but it shows the problem) below. In this case, I have two different Borgs because the class names (and I guess the class) are seen as different by the interpreter.

Is there a way to use the Borg in that case without reworking the module architecture?

Module borg.py

import borg2

class Borg:
    _we_are_one = {}

    def __init__(self):
        self.__dict__ = Borg._we_are_one
        try:
            self.name
        except AttributeError:
            self.name = "?"
        print self.__class__, id(self.__dict__)

def fct_ab():
    a = Borg()
    a.name = "Bjorn"

    b = Borg()
    print b.name

if __name__ == "__main__":
    fct_ab()
    borg2.fct_c()

Module borg2.py

import borg

def  fct_c():
    c = borg.Borg()
    print c.name

The result is

__main__.Borg 40106720
__main__.Borg 40106720
Bjorn
borg.Borg 40106288
?

EDIT: In order to clarify my problem: Why does Python consider __main__.Borg and borg.Borg has two different classes?

+1  A: 

It's not the class names that is the problem. I'm not entirely sure why Python see the Borg class and the borg.Borg class as different, perhaps it's because you run this from __main__, I think python does not realize that __main__ and borg is the same module.

The solution is easy. Change fct_ab to:

def fct_ab():
    import borg
    a =  borg.Borg()
    a.name = "Bjorn"

    b = borg.Borg()
    print b.name

This solves the problem.

Lennart Regebro
It doesn't make any difference in my case :-(
luc
Strange, it should.
Lennart Regebro
which version of python and which os?
luc
Ubuntu, and any version.
Lennart Regebro
Well, in any case the accepted answer is a cleaner way of doing it.
Lennart Regebro
+2  A: 

The problem only occurs in your main-function. Move that code to its own file and everything is as you'd expect. This code

import borg
import borg2

if __name__ == "__main__":
    borg.fct_ab()
    borg2.fct_c()

delivers this output:

borg.Borg 10438672
borg.Borg 10438672
Bjorn
borg.Borg 10438672
Bjorn
Ralph
It works but I would have to rework my module architecture. A bit more complex in my real app.
luc
I've accepted the answer which is ok for the question i've asked.
luc
A: 

I've fixed the issue in my real application by fixing an error in the import.

In fact, I have two different modules using the same 3rd module.

The 1st one was importing mypackage.mymodule while the 2nd one was importing mymodule. mypackage is installed as a python egg and the code I was working on is on my development folder.

So both codes were importing different modules and I guess that it is normal to have two different classes in this case.

Regarding the example code I've used, the problem comes from the current modules to receive the main as name. I've tried to rename by doing __name__ = 'borg'. It works but it breaks the if __name__ == "__main__" condistion. As a conclusion, I would say that mutual inclusion must be avoid and is in most cases not necessary.

Thanks all for your help.

luc
+1  A: 

After a long day of struggling with Singletons and Borg, my conclusion is the following:

It seems that a Python module imported multiple times using different 'import paths' is actually imported multiple times. If that module contains a singleton, you get multiple instances.

Example:

myproject/
  module_A
  some_folder/
    module_B
    module_C

If module_A imports module_C using from myproject.some_folder import module_C and module_B imports the same module_C using import module_C, the module is actually imported twice (at least according to my observations). Usually, this doesn't matter, but for singletons or borg, you actually get 2 instances of what should be unique. (That's 2 sets of borgs sharing 2 different internal states).

Solution: Give yourself an import statement convention and stick to it: I import all modules starting from a common root folder, even if the module file is located parallel to the one I am working on, so in the example above, both module_A and module_B import module_C using from myproject.some_folder import module_C.

ssc