11

Given two modules, main and x with the following contents:

main:

class Singleton(object):
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
        cls._instance.x = 10
        return cls._instance
uvw = Singleton()

if __name__ == "__main__":
    print(id(uvw))
    uvw.x += 10
    print(uvw.x)
    import x

and x, respectively:

import main

print(id(main.uvw))
print(main.uvw.x)

I would now expect that executing main would yield the same IDs and the value twenty in both instances, but what I get is this:

$ python main.py
140592861777168
20
140592861207504
10

Is there any way I can ensure that uvw is the same object at both places?

Ben
  • 51,770
  • 36
  • 127
  • 149
dom0
  • 7,356
  • 3
  • 28
  • 50
  • Note that the entire point of your `__new__` method is to prevent you from needing to access `main.uvw`, since `Singleton()` is guaranteed to return the same instance each time anyway. – Eric Nov 11 '12 at 12:18
  • 1
    So `main` is calling `x` which is calling `main`...? This is a recipe for confusion/disaster. – Andy Hayden Nov 11 '12 at 12:44
  • possible duplicate of [Importing modules: \_\_main\_\_ vs import as module](http://stackoverflow.com/questions/13181559/importing-modules-main-vs-import-as-module) – Martijn Pieters Nov 11 '12 at 12:55
  • You are both using the `__main__` and the `x` module, which are separate namespaces. See the duplicate. – Martijn Pieters Nov 11 '12 at 12:56

3 Answers3

8

I reckon the problem is that your Singleton class is somehow being reloaded, and thus loses its _instance field in the second module.


I think this will work:

singleton.py:

class Singleton(object):
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
        cls._instance.x = 10
        return cls._instance

a.py:

from singleton import Singleton
uvw = Singleton()
print(id(uvw))
uvw.x += 10
print(uvw.x)

b.py:

from singleton import Singleton
uvw = Singleton()
print(id(uvw))
uvw.x += 10
print(uvw.x)

main.py

import a
import b
Eric
  • 95,302
  • 53
  • 242
  • 374
7

Python loads each module by name once (unless reload(module) is called). If you run main.py, the module is __main__ (try printing uvw.__class__.__module__). When x imports main, the module called main is being loaded for the first time.

If you defined uvw in a third module, or in x -- as long as it is imported in the same way into __main__ and x -- it would be the same object.

joeln
  • 3,563
  • 25
  • 31
1

I found out that the problem is that main is loaded twice when it's executed from the command line, one time as __main__ and the second time when imported by x as main.

I found a very evil hack to circumvent the second load:

sys.modules["main"] = sys.modules["__main__"]

Separating the main module and the singleton class is not favorable in my case.

dom0
  • 7,356
  • 3
  • 28
  • 50
  • 3
    To avoid evil hack you could define `uvw` in a module that is not executed as a script and then just import that module in you main script – jfs Nov 11 '12 at 12:27