Re: Need help subclassing Borg
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/Cookbook/Python/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. -- http://mail.python.org/mailman/listinfo/python-list
Re: Need help subclassing Borg
On Sun, 08 May 2005 02:42:09 +1000, Steven D'Aprano <[EMAIL PROTECTED]> wrote: >On Sat, 07 May 2005 08:35:21 -0700, [EMAIL PROTECTED] 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 "", line 1, in ? > File "", 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 -- http://mail.python.org/mailman/listinfo/python-list
Re: Need help subclassing Borg
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 "", 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.) -- http://mail.python.org/mailman/listinfo/python-list
Re: Need help subclassing Borg
On Sat, 07 May 2005 22:28:34 +1000, Steven D'Aprano <[EMAIL PROTECTED]> wrote: >I've been working with the Borg design pattern from here: >http://aspn.activestate.com/ASPN/Cookbook/Python/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__.__name__, {}) ... >>> 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 "", 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__': , '_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 -- http://mail.python.org/mailman/listinfo/python-list
Re: Need help subclassing Borg
On Sat, 07 May 2005 08:35:21 -0700, [EMAIL PROTECTED] 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 "", line 1, in ? File "", 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. -- http://mail.python.org/mailman/listinfo/python-list
Re: Need help subclassing Borg
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() [EMAIL PROTECTED]:~$ ./test2.py feathers fur [EMAIL PROTECTED]:~$ -- http://mail.python.org/mailman/listinfo/python-list
Need help subclassing Borg
I've been working with the Borg design pattern from here: http://aspn.activestate.com/ASPN/Cookbook/Python/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. -- http://mail.python.org/mailman/listinfo/python-list