|
Prev: Parsing MIME-encoded data in an HTTP request
Next: How to bypass Windows 'cooking' the I/O? (One more time, please)
From: Matthew Fitzgibbons on 3 Jul 2008 19:11 Urizev wrote: > Hi everyone > > I have developed the singleton implementation. However I have found a > strange behaviour when using from different files. The code is > attached. > > Executing main > new MySet object > No singleton instance > New singleton: > <__main__.Singleton instance at 0x2b98be474a70> > new MySet object > There is a singlenton instance > new Member > new MySet object > No singleton instance > New singleton: > <myset.Singleton instance at 0x2b98be474d88> > new Member > new MySet object > There is a singlenton instance > new Member > new MySet object > There is a singlenton instance > > I do not know why, but it creates two instances of the singleton. Does > anybody know why? > > Regards > > > ------------------------------------------------------------------------ > > -- > http://mail.python.org/mailman/listinfo/python-list I've run into a similar problem. Basically, when you refer to a class from __main__ (i.e., the .py file you're actually running) versus from an imported module, Python doesn't realize they're the same class. Your Singleton implementation is creating one instance for __main__ and one for everything else. I'm sure there's someone around here who can say why Python behaves this way. You should be fine if you can restructure your code so you don't use your Singleton from __main__. In my case, I added a new main.py file. -Matt
From: George Sakkis on 3 Jul 2008 21:15 On Jul 3, 6:58 pm, Urizev <uri...(a)gmail.com> wrote: > Hi everyone > > I have developed the singleton implementation. However I have found a > strange behaviour when using from different files. The code is > attached. > > Executing main > new MySet object > No singleton instance > New singleton: > <__main__.Singleton instance at 0x2b98be474a70> > new MySet object > There is a singlenton instance > new Member > new MySet object > No singleton instance > New singleton: > <myset.Singleton instance at 0x2b98be474d88> > new Member > new MySet object > There is a singlenton instance > new Member > new MySet object > There is a singlenton instance > > I do not know why, but it creates two instances of the singleton. Does > anybody know why? Because __init__() is called to initialize the state of an object *after* it has already been created. You should create a "new-style" class and define __new__() instead. Here's a working version: class Singleton(object): # new-style class def __new__(cls, *args, **kwds): # return the singleton (if already created) try: return cls.__dict__['__singleton'] except KeyError: # raised only the first time for a given class # create the singleton and store it to the class namespace singleton = object.__new__(cls, *args, **kwds) setattr(cls, '__singleton', singleton) return singleton class X(Singleton): def __init__(self, a): self.a = a assert X(1) is X(2) Note however that the classic Singleton pattern is usually frowned upon in Python; the preferred approach is to use (module level) globals. Also search for the "Borg pattern". George
From: Peter Otten on 4 Jul 2008 01:56 Urizev wrote: > Hi everyone > > I have developed the singleton implementation. However I have found a > strange behaviour when using from different files. The code is > attached. > > Executing main > New singleton: > <__main__.Singleton instance at 0x2b98be474a70> > New singleton: > <myset.Singleton instance at 0x2b98be474d88> > I do not know why, but it creates two instances of the singleton. Does > anybody know why? Do you see it now I snipped the irrelevant output? The problem is the structure of your program. The myset module is imported twice by Python, once as "myset" and once as "__main__". Therefore you get two distinct MySet classes, and consequently two distinct MySet.__instance class attributes. Move the if __name__ == "__main__": ... statements into a separate module, e. g. main.py: import myset import member if __name__ == "__main__": print "Executing main" set1 = myset.MySet() set2 = myset.MySet() mbr1 = member.Member() mbr2 = member.Member() mbr3 = member.Member() Now main.py and member.py share the same instance of the myset module and should work as expected. Peter
From: Ben Finney on 4 Jul 2008 03:12 Peter Otten <__peter__(a)web.de> writes: > The problem is the structure of your program. The myset module is > imported twice by Python, once as "myset" and once as "__main__". Yes, this is the problem. Each module imports the other. > Therefore you get two distinct MySet classes, and consequently two > distinct MySet.__instance class attributes. Are you sure? This goes against my understanding: that 'import foo' will not re-import a module that's already been imported, but will instead simply return the existing module. So, I think if one evaluated 'myset is __main__', you'd find they are exactly the same module under different names; and therefore that there is only *one* instance of 'MySet', again under two names. -- \ “Science doesn't work by vote and it doesn't work by | `\ authority.” —Richard Dawkins, _Big Mistake_ (The Guardian, | _o__) 2006-12-27) | Ben Finney
From: Matthew Fitzgibbons on 4 Jul 2008 03:52
Ben Finney wrote: > Peter Otten <__peter__(a)web.de> writes: > >> The problem is the structure of your program. The myset module is >> imported twice by Python, once as "myset" and once as "__main__". > > Yes, this is the problem. Each module imports the other. > >> Therefore you get two distinct MySet classes, and consequently two >> distinct MySet.__instance class attributes. > > Are you sure? This goes against my understanding: that 'import foo' > will not re-import a module that's already been imported, but will > instead simply return the existing module. > > So, I think if one evaluated 'myset is __main__', you'd find they are > exactly the same module under different names; and therefore that > there is only *one* instance of 'MySet', again under two names. > You can see that they're distinct by checking the addresses (the instances in the OP also have different addresses). Besides, __main__ isn't imported normally. -Matt |