Is a Borg rebellion possible? (a metaclass question)

André andre.roberge at gmail.com
Fri Sep 7 15:13:41 EDT 2007


On Sep 7, 3:53 pm, Steve Holden <st... at holdenweb.com> wrote:
> André wrote:
> > On Sep 7, 10:27 am, Carsten Haese <cars... at uniqsys.com> wrote:
> >> On Fri, 2007-09-07 at 12:31 +0000, André wrote:
> >>> 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 instances of that class will share
> >>> the
> >>>     same state, provided that they don't override __new__; otherwise,
> >>>     remember to use Borg.__new__ within the overriden class.
> >>>     '''
> >>>     _shared_state = {}
> >>>     def __new__(cls, *a, **k):
> >>>         obj = object.__new__(cls, *a, **k)
> >>>         obj.__dict__ = cls._shared_state
> >>>         return obj
> >>> ----
> >>> This has worked very well so far, but is starting to impose some
> >>> unwanted constraints on my program design.
> >>> What I would like to do is, to put it figuratively, create a Borg
> >>> rebellion with various splinter groups.  In concrete Python terms, I
> >>> would like to have
> >>> class MyClass(Borg, ...):
> >>>    ...
> >>> seven_of_nine = MyClass(...)  # part of group "BORG"
> >>> two_of_nine = MyClass(...)
> >>> splinter1 = MyClass(..., group='splinter')
> >>> splinter2 = MyClass(..., group='splinter')
> >>> and have splinter 1 and splinter2 share the same state, but a
> >>> different state than the one shared by members of the BORG collective.
> >>> Any suggestions from the metaclass experts?
> >> You don't need a metaclass. Just turn _shared_state into a dictionary of
> >> shared states, keyed by the group name:
>
> >> class SplinterBorg(object):
> >>     _shared_states = {}
> >>     def __new__(cls, *a, **k):
> >>         group = k.pop("group","BORG")
> >>         obj = object.__new__(cls, *a, **k)
> >>         obj.__dict__ = cls._shared_states.setdefault(group,{})
> >>         return obj
>
> >> HTH,
>
> >> --
> >> Carsten Haesehttp://informixdb.sourceforge.net
>
> > Unfortunately, it fails.  Here's what I tried, followed by the
> > traceback
> > class SplinterBorg(object):
> >     _shared_states = {}
> >     def __new__(cls, *a, **k):
> >         group = k.pop("group","BORG")
> >         obj = object.__new__(cls, *a, **k)
> >         obj.__dict__ = cls._shared_states.setdefault(group,{})
> >         return obj
>
> > class MyClass(SplinterBorg):
> >    def __init__(self, name):
> >        self.name = name
>
> > a1 = MyClass('a')
> > a2 = MyClass('aa')
> > b1 = MyClass('b', group="B")
>
> > Traceback (most recent call last):
> >   File "test.py", line 15, in <module>
> >     b1 = MyClass('b', group="B")
> > TypeError: __init__() got an unexpected keyword argument 'group'
>
> Because your subclass signature is completely wrong. Why did you feel
> you had to add an __init__() method to your subclass? This has two bvad
> effects:


Because this is what I need to do currently with using the standard
Borg class, and is something I would like to be able to do.  Here's a
simplified version of the current usage I have
=====
class Borg(object):
    _shared_state = {}
    def __new__(cls, *a, **k):
        obj = object.__new__(cls, *a, **k)
        obj.__dict__ = cls._shared_state
        return obj

class BorgConsole(Borg, SingleConsole):
    '''Every BorgConsole share a common state'''
    def __init__(self, locals={}, filename="Crunchy console"):
        SingleConsole.__init__(self, locals, filename=filename)

=====
and it is called via something like
a_console = BorgConsole(locals)

where locals is a previously defined dict.   Note that a number of
such instances are created dynamically as the program is used.

What I would like to do is to be able to add a "page_id"   (the Borg
group referred to my previous message), so that I could call

a_console = BorgConsole(locals, page_id)
where page_id would be an optional argument, defaulting to the BORG
group, as mentioned in my original post.

I must admit I did not try with keywords arguments ... and will not be
for a couple of hours while I am at work.


>
> 1. It stops the super-class's __init__() method from being called, and
>
I don't understand why this is so here, and not with the usual Borg
case as I used it...

> 2. It breaks the calling syntax specified in the superclass.
>
> All you really need is to create your SplinterBorgs with appropriate
> group names, you don't neef subclasses at all:
>
> a1 = SplinterBorg(group="one")
> a2 = SplinterBorg(group="two")
>
> and so on.
>
> If you want to create subclasses then they should work like this:
>
> class MyBorg1(SplinterBorg):
>      def __init__(self):
>          SplinterBorg.__init__(self, group='borg1')
>
> and so on, with a different group for each. But this seems over complicated.
>

I do need subclasses (I think) as my classes inherit from more than
the SplinterBorg class...  I'll  see what I can do following some of
your suggestions.

Thanks for the reply,

André

> regards
>   Steve
> --
> Steve Holden        +1 571 484 6266   +1 800 494 3119
> Holden Web LLC/Ltd          http://www.holdenweb.com
> Skype: holdenweb      http://del.icio.us/steve.holden
> --------------- Asciimercial ------------------
> Get on the web: Blog, lens and tag the Internet
> Many services currently offer free registration
> ----------- Thank You for Reading -------------





More information about the Python-list mailing list