singleton objects with decorators

U

Uwe Mayer

Hi,

I've been looking into ways of creating singleton objects. With Python2.3 I
usually used a module-level variable and a factory function to implement
singleton objects.

With Python2.4 I was looking into decorators. The examples from PEP 318
http://www.python.org/peps/pep-0318.html#examples

don't work - AFAIK because:
- you cannot decorate class definitions (why was it left out?)
- __init__ must return None


However, you can use the decorator:

def singleton(f):
instances = {}
def new_f(*args, **kwargs):
if (f not in instances):
instances[f] = f(*args, **kwargs)
return instances[f]
new_f.func_name = f.func_name
new_f.func_doc = f.func_doc
return new_f

with a class that overwrites the __new__ methof of new-style classes:

class Foobar(object):
def __init__(self):
print self

@singleton
def __new__(self):
return object.__new__(Foobar)


Is this particularly ugly or bad?

Thanks for comments,
Ciao
Uwe
 
S

Steven Bethard

Uwe said:
Hi,

I've been looking into ways of creating singleton objects. With Python2.3 I
usually used a module-level variable and a factory function to implement
singleton objects.

With Python2.4 I was looking into decorators. The examples from PEP 318
http://www.python.org/peps/pep-0318.html#examples

don't work - AFAIK because:
- you cannot decorate class definitions (why was it left out?)
- __init__ must return None


However, you can use the decorator:

def singleton(f):
instances = {}
def new_f(*args, **kwargs):
if (f not in instances):
instances[f] = f(*args, **kwargs)
return instances[f]
new_f.func_name = f.func_name
new_f.func_doc = f.func_doc
return new_f

with a class that overwrites the __new__ methof of new-style classes:

class Foobar(object):
def __init__(self):
print self

@singleton
def __new__(self):
return object.__new__(Foobar)

Is this particularly ugly or bad?

Seems a little confoluted. Why can't you just use something like:

class Singleton(object):
def __new__(cls, *args, **kwargs):
try:
return cls.__instance__
except AttributeError:
instance = cls.__instance__ = super(Singleton, cls).__new__(
cls, *args, **kwargs)
return instance

class Foobar(Singleton):
def __init__(self):
print self

?

STeVe
 
B

Bengt Richter

Hi,

I've been looking into ways of creating singleton objects. With Python2.3 I
usually used a module-level variable and a factory function to implement
singleton objects.

With Python2.4 I was looking into decorators. The examples from PEP 318
http://www.python.org/peps/pep-0318.html#examples

don't work - AFAIK because:
- you cannot decorate class definitions (why was it left out?)
- __init__ must return None


However, you can use the decorator:

def singleton(f):
instances = {}
def new_f(*args, **kwargs):
if (f not in instances):
instances[f] = f(*args, **kwargs)
return instances[f]
new_f.func_name = f.func_name
new_f.func_doc = f.func_doc
return new_f

with a class that overwrites the __new__ methof of new-style classes:

class Foobar(object):
def __init__(self):
print self

@singleton
def __new__(self):
return object.__new__(Foobar)


Is this particularly ugly or bad?

Thanks for comments,

I thought of a different approach. The singleton function here
takes arguments for the initial instance of a class, and instantiates it,
and then modifies the class's __new__ and __init__ to return the initial
instance and prevent further initialization.

Used directly, as normal function decorators can be (i.e., fun = deco(fun)
or fun = deco(args)(fun)), singleton works (not counting bugs ;-) as is.

To invoke it as decorator demands a trick workaround using an intermediate
workaround decorator and a dummy funcion definition synonymous with the
class to be decorated (which mus pre-exist for this).

BTW, this is different from the class-decorator-as-sugar-for-metaclass,
(which I suggested previously) since it take one class argument vs arguments
for the metaclass __new__ etc.


I added a singularize decorator for when you don't immediately want to
specify the first initiazization parameters, but want the first instance
to to become the singleton instance whenever that happens later.

So here's some hacks to play with:

----< singleton.py >-----------------------------------------------
def singleton(*args, **kw):
"""decorator cacheing singleton instance immediately"""
def singdeco(cls):
assert isinstance(cls, type)
inst = cls(*args, **kw)
cls.__new__ = staticmethod(lambda *a, **kw: inst)
cls.__init__ = staticmethod(lambda *a, **kw: None) # no re-init
return cls
return singdeco

import sys
def workaround(f):
cls = sys._getframe(1).f_locals.get(f.func_name)
if cls is None:
cls = sys._getframe(1).f_globals.get(f.func_name)
return cls

def singularize(cls):
"""decorator setting singleton-making mousetrap"""
oldnew = cls.__new__
def __new__(cls, *args, **kw):
inst = oldnew(cls)
inst.__init__(*args, **kw)
cls.__new__ = staticmethod(lambda *a,**kw: inst)
cls.__init__ = staticmethod(lambda *a, **kw: None)
return inst
cls.__new__ = staticmethod(__new__)
return cls

def test():
class Foobar(object): pass
Foobar = singleton()(Foobar)
print Foobar
print [Foobar() for x in xrange(2)]

class Boobar(object):
def __init__(self, v):
print self, v
self.v = v
@singleton(123)
@workaround
def Boobar(): pass # dummy used by workaround for name

print Boobar
print [Boobar(x) for x in xrange(2)]
print [Boobar(x).v for x in xrange(2)]

class Gee(object):
def __init__(self): print 'Gee:', self

Gee = singularize(Gee)
print Gee
print [Gee() for x in xrange(2)]

class Haw(object):
def __init__(self, *args, **kw):
self.args = args
self.kw =kw

Haw = singularize(Haw)
haw = Haw(1,2L, 3.5, s='string', more='example')
print vars(haw)
print vars(Haw(111, a='222'))
print [Haw(), Haw()]
print [Haw().args for i in xrange(len(Haw().args))]
print [Haw().kw['s'], Haw().kw['more']]


if __name__ == '__main__':
test()
-------------------------------------------------------------------
No guarantees, mind ;-)

Output, showing single instances and no repeat initialization:

<class '__main__.Foobar'>
[<__main__.Foobar object at 0x02F03BEC>, <__main__.Foobar object at 0x02F03BEC>]
<__main__.Boobar object at 0x02F03DCC> 123
<class '__main__.Boobar'>
[<__main__.Boobar object at 0x02F03DCC>, <__main__.Boobar object at 0x02F03DCC>]
[123, 123]
<class '__main__.Gee'>
Gee: <__main__.Gee object at 0x02F03E8C>
[<__main__.Gee object at 0x02F03E8C>, <__main__.Gee object at 0x02F03E8C>]
{'args': (1, 2L, 3.5), 'kw': {'s': 'string', 'more': 'example'}}
{'args': (1, 2L, 3.5), 'kw': {'s': 'string', 'more': 'example'}}
[<__main__.Haw object at 0x02F03F0C>, <__main__.Haw object at 0x02F03F0C>]
[1, 2L, 3.5]
['string', 'example']

Regards,
Bengt Richter
 
S

Steven Bethard

Uwe said:
I've been looking into ways of creating singleton objects.

It strikes me that I've never wanted or needed a singleton object.
Would you mind sharing your use case? I'm just curious.

Thanks,

STeVe
 
U

Uwe Mayer

Tuesday said:
It strikes me that I've never wanted or needed a singleton object.
Would you mind sharing your use case? I'm just curious.

I am using a class to manage configuration settings in an application. This
object should only existe once so that when the user
changes a setting through a configuration dialog the change imminent in all
locations where access to config settings are needed.

I was using a factory function bevore, but since I am starting to use Python
2.4 and I remembered having read about a singleton-decorator I went to look
deeper into the possibilities.

Ciao
Uwe
 
S

Steven Bethard

Uwe said:
I am using a class to manage configuration settings in an application. This
object should only existe once so that when the user
changes a setting through a configuration dialog the change imminent in all
locations where access to config settings are needed.

Ahh, I see. I would typically just use a module in this situation,
where the configuration settings were just names global to the module.
Is there a benefit to using a singleton object over using just a module?

STeVe
 
R

Reinhold Birkenfeld

Uwe said:
I am using a class to manage configuration settings in an application. This
object should only existe once so that when the user
changes a setting through a configuration dialog the change imminent in all
locations where access to config settings are needed.

In this case, you may want to read

http://www.aleax.it/5ep.html


Grüße
Reinhold
 
F

Fredrik Lundh

Uwe said:
I am using a class to manage configuration settings in an application. This
object should only existe once so that when the user
changes a setting through a configuration dialog the change imminent in all
locations where access to config settings are needed.

So use a module-level object, and be done with it.

Or if you're using an application object (you should), just add a config object
to the application object (app.config.param = ...).

Or use a module to hold the configuration data (import config; config.param = ...);
serializing to and from module variables work really well in Python.
I was using a factory function bevore, but since I am starting to use Python
2.4 and I remembered having read about a singleton-decorator I went to look
deeper into the possibilities.

I'm sure your users would love you even more if you spend that time and
energy adding stuff to the application... ;-)

</F>
 
M

Michele Simionato

Steven Bethard:
It strikes me that I've never wanted or needed a singleton object.
Would you mind sharing your use case? I'm just curious.

"Singleton" is the most idiotic pattern ever. If you want an instance,
just
instantiate your class once. If a class should have only one instance,
you can just document it. What I find usuful is "memoize", which
contains "Singleton" as a special case. So I use memoize even
for singleton would-be, i.e. logfiles and databases connections
(memoizing the connections, if I try to open a database twice with the
same parameters, I am returned an instance of the already opened
database).

Michele Simionato
 
U

Uwe Mayer

Ahh, I see. I would typically just use a module in this situation,
where the configuration settings were just names global to the module.
Is there a benefit to using a singleton object over using just a module?

Basically I am using a module. The config file is stored in
$HOME/.<app>/<app>.conf where the user can go and edit it. It is a working
python program which globally declares variables.
I cannot simply import this module as it does not lie in the path and I am
not too fond of dynamically cluttering sys.path to my needs. My intend was
to make it look as little complicated as possible (for the user) while
retaining maximum flexibility.

Therefore I wrote a class, subclassing a dict, which executes the config
file and takes up the variables into its namespace. Afterwards I update the
dict with default-values (in case the user kicked some vars out) or
manipulate the read-in config variables, in case the format changed.

When the application closes the Singleton is written back to the config file
in the user home by using the PrettyPrinter and substituting variables in a
rather longer descriptive text. That way the user always has a nicely
formatted, descriptive configuration file - I thought that was rather
straight forward. :/

Ciao
Uwe
 
U

Uwe Mayer

Tuesday said:
Steven Bethard:

"Singleton" is the most idiotic pattern ever. If you want an instance,
just
instantiate your class once. If a class should have only one instance,
you can just document it. What I find usuful is "memoize", which
contains "Singleton" as a special case. So I use memoize even
for singleton would-be, i.e. logfiles and databases connections
(memoizing the connections, if I try to open a database twice with the
same parameters, I am returned an instance of the already opened
database).

"Singleton" is simple (like the wheel), but that does not make it stupid.
There are two aspects that are important:

1. a Singleton has one, very simple property and virtually everyone knows
what you talk about when you explain that you used a "Singleton". In this
case its just a technical term. We need technical terms.

2. the property of a Singleton, i.e. there is only one, is important - you
use it yourself through memoize. That is just a more flexible
implementation of having one instance of whatever you memoize.

Using @memoize on the __new__ method works very well and is flexible enough
to be used with any function call. Thanks for the tip.

Ciao
Uwe
 
B

Bengt Richter

Steven Bethard:

"Singleton" is the most idiotic pattern ever. If you want an instance,
just
instantiate your class once. If a class should have only one instance,
you can just document it. What I find usuful is "memoize", which
contains "Singleton" as a special case. So I use memoize even
for singleton would-be, i.e. logfiles and databases connections
(memoizing the connections, if I try to open a database twice with the
same parameters, I am returned an instance of the already opened
database).

For most user application purposes, I agree,
just use a single instance like a responsible adult ;-)

But isn't bool supposed to be a singleton class/type ?
>>> [bool(x) for x in 0, 0.0, [], {}, False] [False, False, False, False, False]
>>> [id(bool(x)) for x in 0, 0.0, [], {}, False]
[505014288, 505014288, 505014288, 505014288, 505014288]

Regards,
Bengt Richter
 
F

Fredrik Lundh

Bengt said:
But isn't bool supposed to be a singleton class/type ?
[bool(x) for x in 0, 0.0, [], {}, False] [False, False, False, False, False]
[id(bool(x)) for x in 0, 0.0, [], {}, False]
[505014288, 505014288, 505014288, 505014288, 505014288]

"False" is an ordinary global object, not an object factory or a singleton class.

</F>
 
M

Michele Simionato

Uwe said:
"Singleton" is simple (like the wheel), but that does not make it stupid.
There are two aspects that are important:

1. a Singleton has one, very simple property and virtually everyone knows
what you talk about when you explain that you used a "Singleton". In this
case its just a technical term. We need technical terms.

No. Not everybody knows about Singleton. It is an acquired knowledge.
The reason why I am so opposed to Singletons is that a while ago I was
in the condition of not knowing what a Singleton was. However,
everybody
was talking about Singletons, posting recipes of how to implement them
in
Python, etc. So I figured out it was a very important concept and that
I was missing something, since I was incapable of understand its
relevance.
It was only after many months that I understood that there was really
nothing
more to it. I am the kind of person that can learn easily even very
hard
concept, if I can see and use/interest for them. However, I find
extremely
difficult to learn even simple concepts if they do not make sense for
me.
Singleton did not make sense for me since I did not have an use case
for
it. Now, I have some use case for it, but still I think these use cases
are much better managed by memoize. BTW, when I first heard about
memoize,
I understood it instantenously, since I had tons of cases where I had
implemented it in my own code without knowing the technique was called
memoize.

There is so much to know. I don't want to waste my time with concepts
that
are not worth it. IMO, Singleton is not worth the fuss, and we would
be better off without a fancy name for it (just tell what it is: a
class returning always the same instance). Let us reserve fancy names
to
worthy concepts.

In my lectures at Oxford next week I have carefully expunged anything
referring to Singletons ;)
2. the property of a Singleton, i.e. there is only one, is important - you
use it yourself through memoize. That is just a more flexible
implementation of having one instance of whatever you memoize.

IMNSHO, the property "there is only one" is not important enough to
deserves
a name. The property "if you have already called this callable with the
same arguments you don't need to recompute it" instead is quite worthy
and subsumes the other concept as a special case. It also gives you
plenty of use case to illustrate it, even to beginner programmers.


Michele Simionato
 
B

Bengt Richter

Bengt said:
But isn't bool supposed to be a singleton class/type ?
[bool(x) for x in 0, 0.0, [], {}, False]
[False, False, False, False, False]
[id(bool(x)) for x in 0, 0.0, [], {}, False]
[505014288, 505014288, 505014288, 505014288, 505014288]

"False" is an ordinary global object, not an object factory or a singleton class.
UIAM, "False" is a string, or a representation of a string ;-)
And the name False is typically found as __builtins__.False unless you
have shadowed it locally or in some module globals, as I'm sure you know.

I was just demonstrating that all the bool(x) _instances_ are the identical
False object in the above, and duck-wise that quacks singleton-like,
even though the True maybe makes it a dualton, since bool does return two distinct instances ;-)

IMO the global False name accessibility is a red herring, since it's the object it is
normally bound to that is the real subject.
True

UIAM, the True and False objects per se are unique and built into boolobject.c
And you can bind all the names you like to them, but bool(0) is always that single
unique object and so is bool(1) its unique object. I don't believe this is an
optimization like that involving the first 100 integer values or so.

It's a weird beast, being a subtype of int also. I'll defer to the BDFL in
http://www.python.org/peps/pep-0285.html

"""
The values False and True will be singletons, like None. Because
the type has two values, perhaps these should be called
"doubletons"? The real implementation will not allow other
instances of bool to be created.
"""

Regards,
Bengt Richter
 
U

Uwe Mayer

Tuesday said:
No. Not everybody knows about Singleton. It is an acquired knowledge.

Well, what isn't?
What I ment to say, but failed to do so more explicitly, was that it is a
term I felt which was generally known to "the programming society". Or that
it is a term that might pop up in a comunity where software design is an
issue.
This of course does not mean that you could not have used it without knowing
that someone had thought of a fancy name for it.

[...]
It was only after many months that I understood that there was really
nothing
more to it.

I agree. There really isn't much to Singletons. There was a time when I also
did not know about Singletons or design pattern in general. But thats
always the case somehow, somewhere.

[...]
In my lectures at Oxford next week I have carefully expunged anything
referring to Singletons ;)

Perhapts you shouldn't. Otherwise people might stumble over the same problem
you did.
IMNSHO, the property "there is only one" is not important enough to
deserves
a name.

The problem here is: it has already a name. It is the probably most simple
pattern there is. And if only it serves as a mind-boggingly example of a
design pattern, why not call it a "singleton". Why call it a "class that
can only be instanciated once"?
I do not yet feel there is being made too much fuss about it. People do not
start name-dropping on singletons. Design pattern in general, perhaps.
The property "if you have already called this callable with the
same arguments you don't need to recompute it" instead is quite worthy
and subsumes the other concept as a special case. It also gives you
plenty of use case to illustrate it, even to beginner programmers.

To step in your argument, you could also call that "caching a function
call".

BTW: @memoize on the __new__ method isn't quite enough. You'll have to call
it on __init__ as well, otherwise it is executed again on the already
initialised object.
Also calling @memoize on the __init__ does not suffice either, because can
call it with different parameters...

Ciao
Uwe
 
S

Steven Bethard

Fredrik said:
Or if you're using an application object (you should), just add a config object
to the application object (app.config.param = ...).

Do you have a link or two that describe what you mean by an "application
object"? The "you should" comment makes me think this is something of a
design pattern, but googling around wasn't able to satisfy my curiosity.

STeVe
 
S

Steven Bethard

Uwe said:
Basically I am using a module. The config file is stored in
$HOME/.<app>/<app>.conf where the user can go and edit it. It is a working
python program which globally declares variables.
I cannot simply import this module as it does not lie in the path and I am
not too fond of dynamically cluttering sys.path to my needs.

Hmmm... Maybe you could use a memoized wrapper to imp.load_source?
I've never used it, but it looks kinda like it might do what you want...

But I guess that probably doesn't really gain you too much over the
Singleton solution...

STeVe
 
M

Michele Simionato

I did not put memoize on __new__. I put it on the metaclass __call__.
Here is my memoize:

def memoize(func):
memoize_dic = {}
def wrapped_func(*args):
if args in memoize_dic:
return memoize_dic[args]
else:
result = func(*args)
memoize_dic[args] = result
return result
wrapped_func.__name__ = func.__name__
wrapped_func.__doc__ = func.__doc__
wrapped_func.__dict__ = func.__dict__
return wrapped_func

class Memoize(type): # Singleton is a special case of Memoize
@memoize
def __call__(cls, *args):
return super(Memoize, cls).__call__(*args)
 

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

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top