468,771 Members | 1,763 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 468,771 developers. It's quick & easy.

Borg vs Singleton vs OddClass

Lie
This is probably unrelated to Python, as this is more about design
pattern. I'm asking your comments about this design pattern that is
similar in functionality to Singleton and Borg: to share states.

I'm thinking about this design pattern (I don't know if anyone has
ever thought of this pattern before):

class OddClass(object):
def __init__(self):
global OddClass
OddClass = self
def __call__():
return self

The OddClass is a class that would overwrite its own class definition
at its first instantiation. OddClass defines __call__ so that
subsequent "instantiation" (technically it is no more an
instantiation, but Duck Typing says it does) of the class would return
the single instance.

It do have a problem though, that you can't do isinstance(a, OddClass)
since the name OddClass no longer refers to the OddClass class
descriptor, but to an instance of OddClass. I don't think that's much
of a problem though since using isinstance() is generally not a good
idea in python (although OddClass do use global which many people,
including me, would usually consider as bad form).

The problem with Borg is that it is not inheritable (in certain
sense[1]) and only work with old-style class (which is due to be
completely removed on py3k)[2], Singleton and OddClass is inheritable.
>>class Singleton(object): ...
s = Singleton()
class A(Singleton): pass
class B(Singleton): pass
a = A()
b = B()
s.foo, a.bar = "bar", 42
b.foo, b.bar
.... Traceback, Attribute Error ...
>>class OddClass(object): ...
s = OddClass()
class A(OddClass): pass
class B(OddClass): pass
a = A()
b = B()
s.foo, a.bar = "bar", 42
b.foo, b.bar
.... Traceback, Attribute Error ...

but for Borg, see [1]

[1] classes that inherits from Borg shares state not only within
children, but also with their parents and cousins. That means
inheriting from Borg is useless, and that also means one Borg code for
every state sharing classes, instead of inheriting from Singleton/
OddClass. In code:
>>class Borg: ...
class A(Borg): ...
class B(Borg): ...
s, a, b = Borg(), A(), B()
s.foo, a.attr = "bar", 42
b.foo, b.attr
"bar" 42
>># we want b.foo and b.attr to raise error since .foo, and .bar isn't B's shared state, it's A's and Borg's shared state
[2] Actually in new-style class, they say Borg can use __slots__, but
they say it'd be slightly more complex
Sep 27 '08 #1
5 1758
Lie wrote:
This is probably unrelated to Python, as this is more about design
pattern. I'm asking your comments about this design pattern that is
similar in functionality to Singleton and Borg: to share states.

I'm thinking about this design pattern (I don't know if anyone has
ever thought of this pattern before):

class OddClass(object):
def __init__(self):
global OddClass
OddClass = self
def __call__():
I'll change this to def __call__(self):
return self

The OddClass is a class that would overwrite its own class definition
at its first instantiation. OddClass defines __call__ so that
subsequent "instantiation" (technically it is no more an
instantiation, but Duck Typing says it does) of the class would return
the single instance.
This seems like a terrible idea to me, but then I never really
understood the appeal of the Singleton pattern, especially in Python.
Singleton and OddClass is inheritable.
>>>class OddClass(object): ...
s = OddClass()
class A(OddClass): pass
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
__init__() takes exactly 1 argument (4 given)

Oops! And assuming you carefully ordered your code so that OddClass
will never be instantiated before it is subclassed (which seems
fragile), you get behavior like this:
>>s = OddClass()
s is OddClass()
True
>>a = A()
s is OddClass()
False
>>a is OddClass()
True
>>a is A()
False
>>a is OddClass()
False

-Miles
Sep 28 '08 #2
On Sat, 27 Sep 2008 11:12:00 -0700, Lie wrote:
This is probably unrelated to Python, as this is more about design
pattern. I'm asking your comments about this design pattern that is
similar in functionality to Singleton and Borg: to share states.

I'm thinking about this design pattern (I don't know if anyone has ever
thought of this pattern before):

class OddClass(object):
def __init__(self):
global OddClass
OddClass = self
def __call__():
return self

I don't think that pattern works as you give it. I suggest you read the
thread "What do you call a class not intended to be instantiated",
started by me on the 21st of September, which covers a similar pattern.

I'm afraid it's a rather long thread, with a lot of people
misunderstanding what I was asking, but still worth reading. If you only
have time to read one post, I suggest you read my reply to Ben Finney,
posted yesterday.

My own feeling is that both your OddClass and my class without instances
are probably solutions looking for a problem. Well, actually, no, that's
too strong: I think the concept of "Class Singleton" is a perfectly valid
solution to certain problems, but it competes with more well-known
solutions like modules and Borg (in Python) and Singletons (the hammer
available in Java and C++). As for which is better, that's partly a
matter of personal taste and partly a matter of familiarity.

It do have a problem though, that you can't do isinstance(a, OddClass)
But you can say "a is OddClass", which is more appropriate for a
Singleton.
The problem with Borg is that it is not inheritable (in certain
sense[1]) and only work with old-style class (which is due to be
completely removed on py3k)[2]
No, there is a new-style Borg. Read the comments here:
http://code.activestate.com/recipes/66531/

The new-style Borg is hardly more complicated than old-style: 6 lines
versus 4.

I like Luke Plant's comment:

"classes and modules are singletons. You don't need singletons in python
simply because classes and modules are always singletons, and they are
also first class objects. They can have everything instances have, and as
import statements don't make copies there is only ever one of them. We
don't need no stinkin' design patterns."

--
Steven
Sep 28 '08 #3
On Sep 27, 2:12*pm, Lie <Lie.1...@gmail.comwrote:
I'm thinking about this design pattern (I don't know if anyone has
ever thought of this pattern before):

class OddClass(object):
* * def __init__(self):
* * * * global OddClass
* * * * OddClass = self
* * def __call__():
* * * * return self

The OddClass is a class that would overwrite its own class definition
at its first instantiation. OddClass defines __call__ so that
subsequent "instantiation" (technically it is no more an
instantiation, but Duck Typing says it does) of the class would return
the single instance.

It do have a problem though, that you can't do isinstance(a, OddClass)
since the name OddClass no longer refers to the OddClass class
descriptor, but to an instance of OddClass.
I recommend against your idiom above. The main issue I have about it
is that it rebinds the symbol implicitly, which is almost always a bad
idea. What if a user does something like "from oddclassmodule import
OddClass"? Then the user will get a new instance every call since it
never rebinds the imported symbol.

Just don't do it this way.

You could rewrite it like this to avoid the implicit rebinding, and to
take care of the isinstance issue as well:

class NotSoOddClass(object):
def __new__(cls):
self = getattr(cls,"_instance",None)
if self is None:
self = cls._instance = object.__new__(cls)
return self
Or you could just use a lazy factory function like this, where the
user is only supposed to use Factory and not create the class
directly:

class _NotOddClass(object):
# nothing odd

def Factory():
obj = getattr(_NotOddClass,"_instance",None)
if obj is None:
obj = _NotOddClass._instance = NotOddClass()
return obj
If you're real kinky you can use a metaclass. There are reasons to
prefer any of these. I'd recommend the factory function unless you
think the users could significantly benefit from type inspection.

Just don't do it by rebinding the class name. That's not nice.
Carl Banks
Sep 28 '08 #4
Lie
On Sep 28, 7:22*am, Miles <semantic...@gmail.comwrote:
Lie wrote:
This is probably unrelated to Python, as this is more about design
pattern. I'm asking your comments about this design pattern that is
similar in functionality to Singleton and Borg: to share states.
I'm thinking about this design pattern (I don't know if anyone has
ever thought of this pattern before):
class OddClass(object):
* *def __init__(self):
* * * *global OddClass
* * * *OddClass = self
* *def __call__():

I'll change this to def __call__(self):
* * * *return self
The OddClass is a class that would overwrite its own class definition
at its first instantiation. OddClass defines __call__ so that
subsequent "instantiation" (technically it is no more an
instantiation, but Duck Typing says it does) of the class would return
the single instance.

This seems like a terrible idea to me, but then I never really
understood the appeal of the Singleton pattern, especially in Python.
Singleton and OddClass is inheritable.
>>class OddClass(object): ...
s = OddClass()
class A(OddClass): pass

Traceback (most recent call last):
* File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
* * __init__() takes exactly 1 argument (4 given)

Oops! *And assuming you carefully ordered your code so that OddClass
will never be instantiated before it is subclassed (which seems
fragile), you get behavior like this:
I test the code what would happen if I do this before posting the
pattern:
>>class OddClass(object): ...
s = OddClass()
class A(OddClass): pass
a = A()
It doesn't give me errors, where are you having the problem?
>s = OddClass()
s is OddClass()
True
>a = A()
s is OddClass()
False
>a is OddClass()
True
>a is A()
False
>a is OddClass()

False
Well, spotted, there is identity problem with this pattern.
-Miles
Sep 28 '08 #5
Lie
On Sep 28, 9:45*am, Steven D'Aprano <st...@REMOVE-THIS-
cybersource.com.auwrote:
On Sat, 27 Sep 2008 11:12:00 -0700, Lie wrote:
This is probably unrelated to Python, as this is more about design
pattern. I'm asking your comments about this design pattern that is
similar in functionality to Singleton and Borg: to share states.
I'm thinking about this design pattern (I don't know if anyone has ever
thought of this pattern before):
class OddClass(object):
* * def __init__(self):
* * * * global OddClass
* * * * OddClass = self
* * def __call__():
* * * * return self

I don't think that pattern works as you give it. I suggest you read the
thread "What do you call a class not intended to be instantiated",
started by me on the 21st of September, which covers a similar pattern.
In fact, that thread inspired this thread.
I'm afraid it's a rather long thread, with a lot of people
misunderstanding what I was asking, but still worth reading. If you only
have time to read one post, I suggest you read my reply to Ben Finney,
posted yesterday.
.... before I decided probably this pattern is probably isn't the
answer to that thread.
My own feeling is that both your OddClass and my class without instances
are probably solutions looking for a problem. Well, actually, no, that's
too strong: I think the concept of "Class Singleton" is a perfectly valid
solution to certain problems, but it competes with more well-known
solutions like modules and Borg (in Python) and Singletons (the hammer
available in Java and C++). As for which is better, that's partly a
matter of personal taste and partly a matter of familiarity.
It do have a problem though, that you can't do isinstance(a, OddClass)

But you can say "a is OddClass", which is more appropriate for a
Singleton.
The problem with Borg is that it is not inheritable (in certain
sense[1]) and only work with old-style class (which is due to be
completely removed on py3k)[2]

No, there is a new-style Borg. Read the comments here:http://code.activestate.com/recipes/66531/

The new-style Borg is hardly more complicated than old-style: 6 lines
versus 4.
Sep 28 '08 #6

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

14 posts views Thread by Mars | last post: by
2 posts views Thread by Rajarshi Guha | last post: by
15 posts views Thread by Jay | last post: by
6 posts views Thread by Steven D'Aprano | last post: by
2 posts views Thread by tobiah | last post: by
10 posts views Thread by =?iso-8859-1?B?QW5kcuk=?= | last post: by
2 posts views Thread by Tobiah | last post: by
reply views Thread by Maric Michaud | last post: by
1 post views Thread by CARIGAR | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.