By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
454,526 Members | 1,618 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 454,526 IT Pros & Developers. It's quick & easy.

singleton objects with decorators

P: n/a
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
Jul 18 '05 #1
Share this Question
Share on Google+
26 Replies


P: n/a
Uwe Mayer wrote:
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
Jul 18 '05 #2

P: n/a
On Mon, 11 Apr 2005 17:26:09 +0200, Uwe Mayer <me*****@hadiko.de> wrote:
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[i] 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
Jul 18 '05 #3

P: n/a
Uwe Mayer wrote:
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
Jul 18 '05 #4

P: n/a
Tuesday 12 April 2005 06:36 am Steven Bethard wrote:
Uwe Mayer wrote:
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.


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
Jul 18 '05 #5

P: n/a
Uwe Mayer wrote:
Tuesday 12 April 2005 06:36 am Steven Bethard wrote:
Uwe Mayer wrote:
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.


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
Jul 18 '05 #6

P: n/a
Uwe Mayer wrote:
Tuesday 12 April 2005 06:36 am Steven Bethard wrote:
Uwe Mayer wrote:
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.


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
Gre
Reinhold
Jul 18 '05 #7

P: n/a
Uwe Mayer wrote:
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.


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>

Jul 18 '05 #8

P: n/a
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

Jul 18 '05 #9

P: n/a
Tuesday 12 April 2005 10:01 am Steven Bethard wrote:
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?


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
Jul 18 '05 #10

P: n/a
On 12 Apr 2005 03:09:48 -0700, "Michele Simionato" <mi***************@gmail.com> wrote:
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).


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
Jul 18 '05 #11

P: n/a
Tuesday 12 April 2005 12:09 pm Michele Simionato wrote:
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).


"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
Jul 18 '05 #12

P: n/a
Bengt Richter wrote:
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>

Jul 18 '05 #13

P: n/a
Uwe Mayer wrote:
"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

Jul 18 '05 #14

P: n/a
On Tue, 12 Apr 2005 13:26:54 +0200, "Fredrik Lundh" <fr*****@pythonware.com> wrote:
Bengt Richter wrote:
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.
__builtins__.False is bool(0)

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
Jul 18 '05 #15

P: n/a
Tuesday 12 April 2005 14:51 pm Michele Simionato wrote:
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
Jul 18 '05 #16

P: n/a
Fredrik Lundh wrote:
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
Jul 18 '05 #17

P: n/a
Uwe Mayer wrote:
Tuesday 12 April 2005 10:01 am Steven Bethard wrote:
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?


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
Jul 18 '05 #18

P: n/a
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)

Jul 18 '05 #19

P: n/a
Tuesday 12 April 2005 17:00 pm Michele Simionato wrote:
I did not put memoize on __new__. I put it on the metaclass __call__.
Here is my memoize:

[...]

Clever, thanks! :)

Ciao
Uwe
Jul 18 '05 #20

P: n/a
Tuesday 12 April 2005 17:00 pm Michele Simionato wrote:
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)


I tried it out and found the following "inconsistency":
class Foobar(object): .... __metaclass__ = Memoize
.... def __init__(self, *args): pass
.... Foobar(1) <__main__.Foobar object at 0x4006f7ec> Foobar(2) <__main__.Foobar object at 0x4006f7cc> Foobar(3)

<__main__.Foobar object at 0x4006f82c>

Unless I'm using it incorrectly (I haven't done much metaclass programming
yet) this is the same problem was with using @memoize on __new__ and
__init__.

Talking so much about singletons I'm not even sure what the definition on
calling a singleton with different constructor parameter values is.

Anyways, a fix for that could be:

class SingletonFactory(type):
single = {}
def __call__(cls, *args):
if (cls not in SingletonFactory.single):
SingletonFactory.single[cls] = super(SingletonFactory,
cls).__call__(*args)
return SingletonFactory.single[cls]
i.e. not caching the parameter values or types.

Uwe
Jul 18 '05 #21

P: n/a
Uhm? If I pass different parameters I want to have
different instances. The Singleton behaviour is recovered
only when I pass always the same arguments, in
particular when I pass 0-arguments:
class Foobar: .... __metaclass__ = Memoize
.... Foobar() <__main__.Foobar object at 0xb7defbcc> Foobar() <__main__.Foobar object at 0xb7defbcc> Foobar()

<__main__.Foobar object at 0xb7defbcc>

Of course if for Singleton you mean "whatever I pass
to the constructor it must always return the same
instance" then this pattern is not a Singleton.
This is why I call it memoize ;)

Jul 18 '05 #22

P: n/a
Tuesday 12 April 2005 18:51 pm Michele Simionato wrote:
Uhm? If I pass different parameters I want to have
different instances. The Singleton behaviour is recovered
only when I pass always the same arguments, in
particular when I pass 0-arguments:
class Foobar: ... __metaclass__ = Memoize
... Foobar() <__main__.Foobar object at 0xb7defbcc> Foobar() <__main__.Foobar object at 0xb7defbcc> Foobar()

<__main__.Foobar object at 0xb7defbcc>

Of course if for Singleton you mean "whatever I pass
to the constructor it must always return the same
instance" then this pattern is not a Singleton.
This is why I call it memoize ;)


:)

I guess it depends on what you want to do with the instance and the
constructor, wether it satisfies the condition to be a "singleton":

If you pass i.e. the timestamp of object creation in the constructor, or the
class name that instanciates the object, a memoized implementation would
not suffice.

On the other hand if you need parameterized implementations of a singleton,
i.e. for each colour 'red', 'green', 'blue' - then a memoized
implementation would be better.

Uwe
Jul 18 '05 #23

P: n/a
Bengt Richter wrote:
[...]
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


It would probably make sense (IMHO) to deny rebinding of True and False
in the same way that 2.4 denies rebinding of None. Given that people
would set True and False themselves in order to make their pre-2.4 code
readable, however, this may overstress backward compatibility.

regards
Steve
--
Steve Holden +1 703 861 4237 +1 800 494 3119
Holden Web LLC http://www.holdenweb.com/
Python Web Programming http://pydish.holdenweb.com/

Jul 18 '05 #24

P: n/a
On 12 Apr 2005 08:00:42 -0700, "Michele Simionato" <mi***************@gmail.com> wrote:
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)

Thanks, that is nice and simple, though caching instances of a class
according to initialization parameters is not quite the same concept
as singleton instances, I think. OTOH, if you want to pass differing
parameters to the same instance of a class, there are lots of methods
(pun ;-) to do that that are clearer than (ab)using the constructor interface.
I.e., what is the difference between shared access to a callable instance
in a module vs shared access to a strange class in the same place?

Hm, just had a thought re memoize: you could give it its own optional
hashing function as a keyword argument, and let it use that as a key
for memoize_dic. Then you could use that to make a singleton(-making) class
or a dual/doubleton-making class like bool, e.g., Bool below

----< memoize.py >--------------------------------------------------------
def memoize(arghash=lambda args:args, method=False):
def _memoize(func):
memoize_dic = {}
def wrapped_func(*args):
key = arghash(args[method:])
if key in memoize_dic:
return memoize_dic[key]
else:
result = func(*args)
memoize_dic[key] = result
return result
wrapped_func.__name__ = func.__name__
wrapped_func.__doc__ = func.__doc__
wrapped_func.__dict__ = func.__dict__
return wrapped_func
return _memoize

def mkPolyton(arghash=lambda args:args):
class Memoize(type): # Singleton is a special case of Memoize
@memoize(arghash, True) # (with arghash=lambda args:0 -> singleton)
def __call__(cls, *args):
return super(Memoize, cls).__call__(*args)
return Memoize

class Bool(int):
__metaclass__ = mkPolyton(lambda args:args and args[0] and 1 or 0)
def __repr__(self): return ('False', 'True')[self]
__str__ = __repr__

def tests(todo):
if '1' in todo:
@memoize()
def square(x): return x*x
print '[id(square(1234))...]: ten have same id:', [id(square(1234))
for x in xrange(10)].count(id(square(1234))) == 10
if '2' in todo:
F = Bool(0) # init cache with proper False value
T = Bool(1) # ditto for True value
print 'T:', T, id(T)
print 'F:', F, id(F)
print '[id(Bool(1..10))...]: ten have same id:', [id(Bool(x))
for x in xrange(1,11)].count(id(T)) == 10

if __name__ == '__main__':
import sys
tests(sys.argv[1:])
--------------------------------------------------------------------------
Result (not exactly a thorough test ;-):

[16:36] C:\pywk\ut>py24 memoize.py 1 2
[id(square(1234))...]: ten have same id: True
T: True 49271436
F: False 49271884
[id(Bool(1..10))...]: ten have same id: True

BTW, I found this page interesting:
http://c2.com/cgi/wiki?SingletonPattern
Regards,
Bengt Richter
Jul 18 '05 #25

P: n/a
Other than using modules, I thought @classmethod took care of this kind of
need:

class SingleThing:
some_values = {"fanciness":0}
def __init__(self):
raise Exception, "not enough preceding stars to be fancy enough"
@classmethod
def why_so_fancy(self):
print "why make every thing so fancy?"

I call this pattern:

"Using a Class to Be Something Single Because It Already Is Single"

or "uactbssbiais", for short.

James

--
James Stroud, Ph.D.
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

http://www.jamesstroud.com/
Jul 18 '05 #26

P: n/a
James Stroud wrote:
Other than using modules, I thought @classmethod took care of this kind of
need:

class SingleThing:
some_values = {"fanciness":0}
def __init__(self):
raise Exception, "not enough preceding stars to be fancy enough"
@classmethod
def why_so_fancy(self):
print "why make every thing so fancy?"

I call this pattern:

"Using a Class to Be Something Single Because It Already Is Single"

or "uactbssbiais", for short.


+1 VOTW (Vocabulation of the Week)

=)

STeVe
Jul 18 '05 #27

This discussion thread is closed

Replies have been disabled for this discussion.