473,395 Members | 1,578 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

Need help subclassing Borg

I've been working with the Borg design pattern from here:
http://aspn.activestate.com/ASPN/Coo...n/Recipe/66531

and I'm having problems subclassing it.

I'm a newbie, so I've probably missed something obvious.

I want two Borg-like classes where all instances share state within each
class, but not between them. This is what I tried:

py> class Borg:
py> _shared_state = {}
py> def __init__(self):
py> self.__dict__ = self._shared_state
py>
py> class Duck(Borg):
py> def __init__(self):
py> Borg.__init__(self)
py> self.covering = "feathers" # all ducks are feathered
py>
py> class Rabbit(Borg):
py> def __init__(self):
py> Borg.__init__(self)
py> self.covering = "fur" # all rabbits are furry
py>
py> bugs = Bunny(); daffy = Duck()
py> daffy.covering
'feathers'
py> bugs.covering
'feathers'

Not what I wanted or expected. What I wanted was for the subclasses Rabbit
and Duck to each inherit Borg-like behaviour, but not to share state with
any other Borgs. In other words, all Ducks share state, and all Rabbits
share state, but Ducks and Rabbits do not share state with each other.

I now see why Ducks and Rabbits are sharing state: they both share the
same __dict__ as all Borg instances. But I don't see how to get the
behaviour I want. (Except by cutting and pasting the Borg code into each
one.) Can anyone help?

Thanks,

Steven.


Jul 19 '05 #1
6 1924
See mr Martellis comment of 2001/09/06 in mentiond recipe, you then get
something like this

-#!/usr/bin/env python
-class Borg(object):
- _shared_state = {}
- def __init__(self):
- self.__dict__ = self._shared_state
-
-class Duck(Borg):
- def __init__(self):
- super(Duck, self).__init__()
- self.__covering = "feathers" # all ducks are feathered
- def covering(self):
- return self.__covering
-
-class Rabbit(Borg):
- def __init__(self):
- super(Rabbit, self).__init__()
- self.__covering = "fur" # all rabbits are furry
- def covering(self):
- return self.__covering
-
-bugs = Rabbit()
-daffy = Duck()
-print daffy.covering()
-print bugs.covering()

martin@ubuntu:~$ ./test2.py
feathers
fur
martin@ubuntu:~$

Jul 19 '05 #2
On Sat, 07 May 2005 08:35:21 -0700, wi******@hotmail.com wrote:
See mr Martellis comment of 2001/09/06 in mentiond recipe, you then get
something like this

-#!/usr/bin/env python
-class Borg(object):
- _shared_state = {}
- def __init__(self):
- self.__dict__ = self._shared_state
-
-class Duck(Borg):
- def __init__(self):
- super(Duck, self).__init__()
- self.__covering = "feathers" # all ducks are feathered
What version of Python are you using? I'm using 2.3.3 and I get this:

py> donald = Duck()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 3, in __init__
TypeError: super() argument 1 must be type, not classobj
- self.__covering = "feathers" # all ducks are feathered
- def covering(self):
- return self.__covering
-
-class Rabbit(Borg):
- def __init__(self):
- super(Rabbit, self).__init__()
- self.__covering = "fur" # all rabbits are furry
- def covering(self):
- return self.__covering


Hmmm... I hate to be ungrateful, but apart from being inelegant, it means
having to write get_attribute() and set_attribute() methods for every
attribute the caller might conceivably use. I'm sure to miss at least one.
*wink*

Either that or muck around with __getattr__ and __setattr__, which is
getting uglier by the minute.

I'm thinking what I might need is a function that generates a Borg-like
class. So I would do something like:

Rabbit = MakeBorgClass()
# Rabbit is now a class implementing shared state
# all instances of Rabbit share the same state
Duck = MakeBorgClass()
# Duck is now a class implementing shared state
# all instances of Duck share the same state
# but instances of Duck do not share state with instances of Rabbit

Problem is, I haven't got the foggiest idea how to implement something
like that. Am I on the right track? Where do I go from here?

Thanks,
Steven.



Jul 19 '05 #3
On Sat, 07 May 2005 22:28:34 +1000, Steven D'Aprano <st***@REMOVETHIScyber.com.au> wrote:
I've been working with the Borg design pattern from here:
http://aspn.activestate.com/ASPN/Coo...n/Recipe/66531

and I'm having problems subclassing it.

I'm a newbie, so I've probably missed something obvious.

I want two Borg-like classes where all instances share state within each
class, but not between them. This is what I tried:

py> class Borg:
py> _shared_state = {}
py> def __init__(self):
py> self.__dict__ = self._shared_state
py>
py> class Duck(Borg):
py> def __init__(self):
py> Borg.__init__(self)
py> self.covering = "feathers" # all ducks are feathered
py>
py> class Rabbit(Borg):
py> def __init__(self):
py> Borg.__init__(self)
py> self.covering = "fur" # all rabbits are furry
py>
py> bugs = Bunny(); daffy = Duck()
py> daffy.covering
'feathers'
py> bugs.covering
'feathers'

Not what I wanted or expected. What I wanted was for the subclasses Rabbit
and Duck to each inherit Borg-like behaviour, but not to share state with
any other Borgs. In other words, all Ducks share state, and all Rabbits
share state, but Ducks and Rabbits do not share state with each other.

I now see why Ducks and Rabbits are sharing state: they both share the
same __dict__ as all Borg instances. But I don't see how to get the
behaviour I want. (Except by cutting and pasting the Borg code into each
one.) Can anyone help?


If you are using old-style classes (which you need for this Borg), then you could
keep different shared state dicts within a _shared_states dict, e.g. based on
the name of the subclassed classes, e.g.,
class Borg: ... _shared_states = {} #note plural
... def __init__(self):
... self.__dict__ = self._shared_states.setdefault(self.__class__.__na me__, {})
... class Duck(Borg): ... def __init__(self):
... Borg.__init__(self)
... self.covering = "feathers" # all ducks are feathered
... class Rabbit(Borg): ... def __init__(self):
... Borg.__init__(self)
... self.covering = "fur" # all rabbits are furry
... bugs = Bunny(); daffy = Duck() Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'Bunny' is not defined

Hm, where'd that Bunny come from?
bugs = Rabbit(); daffy = Duck()
daffy.covering 'feathers' bugs.covering 'fur' vars(Borg) {'__module__': '__main__', '__doc__': None, '__init__': <function __init__ at 0x02EE8D14>, '_sha
red_states': {'Rabbit': {'covering': 'fur'}, 'Duck': {'covering': 'feathers'}}} donald = Duck()
donald.covering 'feathers' roger = Rabbit()
roger.covering 'fur' Borg._shared_states['Duck'] {'covering': 'feathers'} Borg._shared_states['Rabbit']

{'covering': 'fur'}

Since you are calling Borg.__init__(self), you could specify some other
classifier than the implicit class name, e.g., Borg.__init__(self, 'feathered')
vs Borg.__init__(self, 'furred') and use that as the key in the setdefault call.

As mentioned in the recipe discussion, new style classes differ somewhat, but you
can accomplish the same functionality, just that if you have special things like
__slots__ or descriptors, you may have to think about how they might interact with
your shared state access.

Regards,
Bengt Richter
Jul 19 '05 #4
On Sun, 08 May 2005 02:42:09 +1000, Steven D'Aprano wrote:
I'm thinking what I might need is a function that generates a Borg-like
class. So I would do something like:

Rabbit = MakeBorgClass()
# Rabbit is now a class implementing shared state
# all instances of Rabbit share the same state
Duck = MakeBorgClass()
# Duck is now a class implementing shared state
# all instances of Duck share the same state
# but instances of Duck do not share state with instances of Rabbit

Problem is, I haven't got the foggiest idea how to implement something
like that. Am I on the right track? Where do I go from here?


Bengt's answer is better than this track, but this question is worth
answering because it is so wonderfully easy in Python.

Remember class is an executable statement, not a declaration:

Python 2.3.5 (#1, Mar 3 2005, 17:32:12)
[GCC 3.4.3 (Gentoo Linux 3.4.3, ssp-3.4.3-0, pie-8.7.6.6)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
def makeBorg(): .... class Borg(object):
.... _shared_state = {}
.... def __init__(self):
.... self.__dict__ = self._shared_state
.... return Borg
.... Duck = makeBorg()
Rabbit = makeBorg()
d = Duck()
d2 = Duck()
d.cover = "fur"
d2.cover 'fur' r = Rabbit()
r.cover Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: 'Borg' object has no attribute 'cover' r.cover = "feathers"
d.cover 'fur' r2 = Rabbit()
r2.cover 'feathers'


(I flipped around the fur and feathers, but don't feel like fixing it :-) )

Now, the problem with this and the reason why Bengt's is more likely
better is that each of these Borg classes is unrelated, so there's no
using issubclass or anything like that. You *could* hack around this, but
it's not worth it. (It is possible to dynamically choose the bases of a
class; you can't do it in the class statement itself, but you can do
something like:

def makeBorg(base = object):
class Borg(base):
etc.

but this is definitely not the best way to go. Still, as above, it does
have its place other times; I've used it to dynamically pick up whether
the user has certain modules installed and add support depending on the
environment. I often do this when I'm writing something currently embedded
in an app I'm writing, but may have use elsewhere outside of the
environment of the app, allowing me to write code that both takes full
advantage of the app environment, while not being completely tied to it.)
Jul 19 '05 #5
On Sun, 08 May 2005 02:42:09 +1000, Steven D'Aprano <st***@REMOVETHIScyber.com.au> wrote:
On Sat, 07 May 2005 08:35:21 -0700, wi******@hotmail.com wrote:
See mr Martellis comment of 2001/09/06 in mentiond recipe, you then get
something like this

-#!/usr/bin/env python
-class Borg(object):
- _shared_state = {}
- def __init__(self):
- self.__dict__ = self._shared_state
-
-class Duck(Borg):
- def __init__(self):
- super(Duck, self).__init__()
- self.__covering = "feathers" # all ducks are feathered


What version of Python are you using? I'm using 2.3.3 and I get this:

py> donald = Duck()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 3, in __init__
TypeError: super() argument 1 must be type, not classobj
- self.__covering = "feathers" # all ducks are feathered
- def covering(self):
- return self.__covering
-
-class Rabbit(Borg):
- def __init__(self):
- super(Rabbit, self).__init__()
- self.__covering = "fur" # all rabbits are furry
- def covering(self):
- return self.__covering


Hmmm... I hate to be ungrateful, but apart from being inelegant, it means
having to write get_attribute() and set_attribute() methods for every
attribute the caller might conceivably use. I'm sure to miss at least one.
*wink*

Either that or muck around with __getattr__ and __setattr__, which is
getting uglier by the minute.

I'm thinking what I might need is a function that generates a Borg-like
class. So I would do something like:

Rabbit = MakeBorgClass()
# Rabbit is now a class implementing shared state
# all instances of Rabbit share the same state
Duck = MakeBorgClass()
# Duck is now a class implementing shared state
# all instances of Duck share the same state
# but instances of Duck do not share state with instances of Rabbit

Problem is, I haven't got the foggiest idea how to implement something
like that. Am I on the right track? Where do I go from here?

On to new-style classes perhaps? You could have a base class that automatically
gives a subclass its own _shared_state if it isn't there, and tacks that onto
the new instance. That way you don't have to do it in your subclass inits. E.g.,
(warning, not tested beyond what you see. Just thought of this ;-)
class Borgomat(object): ... def __new__(cls, *args, **kw):
... if '_shared_state' not in cls.__dict__:
... cls._shared_state = {}
... obj = object.__new__(cls)
... obj.__dict__ = cls._shared_state
... return obj
... class Duck(Borgomat): ... def __init__(self, **kw):
... self.covering = 'feathers'
... self.__dict__.update(kw)
... daffy = Duck()
daffy.covering 'feathers' Duck._shared_state {'covering': 'feathers'} class Rabbit(Borgomat): ... def __init__(self):
... self.covering = 'fur'
... bugs = Rabbit()
bugs.covering 'fur' Rabbit._shared_state {'covering': 'fur'} bugs.food = 'carrots'
Rabbit._shared_state {'food': 'carrots', 'covering': 'fur'} roger = Rabbit()
roger.food 'carrots'

Oops, forgot to use the optional keyword arg in Duck ...
donald = Duck(food='Disney duck chow')
donald.food 'Disney duck chow' donald.covering 'feathers' daffy.food

'Disney duck chow'

Some shared state may not be all that appropriate ;-)

Regards,
Bengt Richter
Jul 19 '05 #6
On Sat, 07 May 2005 22:28:34 +1000, Steven D'Aprano wrote:
I've been working with the Borg design pattern from here:
http://aspn.activestate.com/ASPN/Coo...n/Recipe/66531

Thanks to everyone who took the time to answer. I've learnt a lot from the
discussion, not the least of which was to watch out for those mysterious
bunnies.
Steven.

Jul 19 '05 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

14
by: Mars | last post by:
I have looked long and hard at Mr. Martelli's Borg recipe: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66531 It is a very useful substitute for a Singleton, but I can't figure out...
2
by: Rajarshi Guha | last post by:
Hi, I'm having a little problem with understanding the working of a singleton and borg class. Basically I nedd an class whose state will be shared across several modules. I found the stuff on the...
15
by: Jay | last post by:
I'm sure this is a really dumb question, but how do you detect a variable type in Python? For example, I want to know if the variable "a" is a list of strings or a single string. How do I do...
2
by: BJörn Lindqvist | last post by:
A problem I have occured recently is that I want to subclass builtin types. Especially subclassing list is very troublesome to me. But I can't find the right syntax to use. Take for example this...
11
by: Brent | last post by:
I'd like to subclass the built-in str type. For example: -- class MyString(str): def __init__(self, txt, data): super(MyString,self).__init__(txt) self.data = data
4
by: Bill Borg | last post by:
Hello, I've got a simple shared property, e.g. Public Class dbObject Private Const m_ID As String = "ID" Public Shared ReadOnly Property ID() As String Get Return m_ID End Get End Property
10
by: =?iso-8859-1?B?QW5kcuk=?= | last post by:
In my application, I make use of the Borg idiom, invented by Alex Martelli. class Borg(object): '''Borg Idiom, from the Python Cookbook, 2nd Edition, p:273 Derive a class form this; all...
2
by: Tobiah | last post by:
I have a class that I call Borg that starts like this: class Borg(dict): static_state = {} def __init__(self): self.__dict__ = self.static_state so that I can access the same data from...
5
by: Lie | last post by:
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...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.