singleton problems

H

harryos

hi
I have been trying out singleton design pattern implementations..I
wrote this,


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


class Mysingle(Singleton):
def __init__(self,name):
self.name=name

if __name__=='__main__':
s1=Mysingle('john')
s2=Mysingle('jim')
s3=Mysingle('jeff')
print 's1=',s1,s1.name
print 's2=',s2,s2.name
print 's3=',s3,s3.name

This is the result I got
s1= <__main__.Mysingle object at 0xb776492c> jeff
s2= <__main__.Mysingle object at 0xb776492c> jeff
s3= <__main__.Mysingle object at 0xb776492c> jeff
/home/dev/eclipse_workspace/pylearn/src/designpatterns.py:11:
DeprecationWarning: object.__new__() takes no parameters
self._instance = super(Singleton, self).__new__(self, *args,
**kwargs)

shouldn't the name of s1,s2,s3 be 'john' instead of 'jeff'?
Also,how do I correct the deprecation problem?Can somebody comment?
 
S

Steven D'Aprano

hi
I have been trying out singleton design pattern implementations..I wrote
this,


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

Since __new__ is called before the instance exists, it doesn't receive an
instance as the first argument. Instead it receives the class. While you
can call the parameter anything you like, it is conventional to call it
cls rather than self.

class Mysingle(Singleton):
def __init__(self,name):
self.name=name

if __name__=='__main__':
s1=Mysingle('john')
s2=Mysingle('jim')
s3=Mysingle('jeff')
print 's1=',s1,s1.name
print 's2=',s2,s2.name
print 's3=',s3,s3.name

This is the result I got
s1= <__main__.Mysingle object at 0xb776492c> jeff
s2= <__main__.Mysingle object at 0xb776492c> jeff
s3= <__main__.Mysingle object at 0xb776492c> jeff
/home/dev/eclipse_workspace/pylearn/src/designpatterns.py:11:
DeprecationWarning: object.__new__() takes no parameters
self._instance = super(Singleton, self).__new__(self, *args,
**kwargs)

shouldn't the name of s1,s2,s3 be 'john' instead of 'jeff'?

No. When you create the instance, it is indeed called 'john'. But then
you call __init__ two more times, you modify it to 'jim' and then 'jeff'.

Also,how do I correct the deprecation problem?

By not passing any arguments to object.__new__.

Try this instead:

class Singleton(object):
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Singleton, self).__new__(cls)
# or if you prefer: object.__new__(cls)
return cls._instance

class Mysingle(Singleton):
def __init__(self, name=None):
if hasattr(self, name):
if name is not None:
raise ValueError(
"cannot give name if instance already exists")
else:
if name is None:
raise ValueError("name is not given")
self.name = name

Or you could choose to just ignore the name if the instance already
exists:

class Mysingle(Singleton):
def __init__(self, name):
if not hasattr(self, name):
self.name = name


Can somebody comment?


Yes. The singleton design pattern is over-rated and frequently
unnecessary. Many people consider it to be an anti-pattern far more often
than it is a pattern -- often people needlessly insist on making classes
singletons when they shouldn't be.

If you do need a singleton, the simplest way in Python is just to use a
module. You initialise the singleton with:

import module

You can do this as many times as you want. Then you call functions on it
with:

module.function(args)

You need, literally, zero extra coding.

Another alternative is to realise that the singleton pattern's focus on
object *identity* is unnecessary if all you want is shared state:

http://code.activestate.com/recipes/66531/
 
J

jimgardener

hi Steven,
can you explain that?I didn't quite get it.
I have a module say 'managerutils' where I have a class
MyManager..

ie,
managerutils.py
----------
class MyManager(object):
def __init__(self):
self.myaddresses={}
...

from another main program ,if I call ,
import managerutils

m1=MyManager()
m2=MyManager()
m3=MyManager()

print m1
print m2
print m3

I get
tm1= <managerutils.MyManager object at 0x9f4f58c>
tm2= <managerutils.MyManager object at 0x9f4f5ac>
tm3= <managerutils.MyManager object at 0x9f4f5cc>
tm4= <managerutils.MyManager object at 0x9f4f5ec>

these would print different instances
thanks
jim
 
A

Arnaud Delobelle

harryos said:
hi
I have been trying out singleton design pattern implementations..I
wrote this,


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


class Mysingle(Singleton):
def __init__(self,name):
self.name=name

if __name__=='__main__':
s1=Mysingle('john')
s2=Mysingle('jim')
s3=Mysingle('jeff')
print 's1=',s1,s1.name
print 's2=',s2,s2.name
print 's3=',s3,s3.name

This is the result I got
s1= <__main__.Mysingle object at 0xb776492c> jeff
s2= <__main__.Mysingle object at 0xb776492c> jeff
s3= <__main__.Mysingle object at 0xb776492c> jeff
/home/dev/eclipse_workspace/pylearn/src/designpatterns.py:11:
DeprecationWarning: object.__new__() takes no parameters
self._instance = super(Singleton, self).__new__(self, *args,
**kwargs)

shouldn't the name of s1,s2,s3 be 'john' instead of 'jeff'?
Also,how do I correct the deprecation problem?Can somebody comment?

That's because overriding __new__ doesn't prevent __init__ from being
executed. The reason for this is that when you do:

MySingle('jeff')

what is executed is:

MySingle.__metaclass__.__call__('jeff')

And as by default, MySingle.__metaclass__ is type (I mean the type
called 'type'), its __call__ method is called. This method calls first
the MySingle.__new__ and then MySingle.__init__ on the result. So you
need to override type.__call__. Here is a very simple implementation to
show you the principle (assuming Python 2.X):


class MetaS(type):
def __call__(self, *args, **kwargs):
# Here, self is the class to be instanciated
instance = getattr(self, "_instance", None)
if instance is None:
instance = super(MetaS, self).__call__(*args, **kwargs)
self._instance = instance
return instance

class Singleton(object):
__metaclass__ = MetaS

class MySingle(Singleton):
def __init__(self, name):
self.name = name
def __str__(self):
return str(self.name)


Now let's see this in action:
'John'

HTH

PS: OTOH, singletons are rarely of use in Python as one can use
module-level instances instead.
 
A

Arnaud Delobelle

Arnaud Delobelle said:
That's because overriding __new__ doesn't prevent __init__ from being
executed. The reason for this is that when you do:

MySingle('jeff')

what is executed is:

MySingle.__metaclass__.__call__('jeff')

Oops. I meant:

MySingle.__metaclass__.__call__(MySingle, 'jeff')
 
B

Bruno Desthuilliers

jimgardener a écrit :
hi Steven,
can you explain that?I didn't quite get it.
I have a module say 'managerutils' where I have a class
MyManager..

What Steven was talking about was to NOT use a class at all. Modules are
objects and have their own namespace. And you can use threading.locals
instead of the module's global namespace if you want to be safe.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top