473,320 Members | 1,828 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,320 software developers and data experts.

Is a Borg rebellion possible? (a metaclass question)

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?

André

Sep 7 '07 #1
10 1494
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 Haese
http://informixdb.sourceforge.net
Sep 7 '07 #2
On Sep 7, 10:27 am, Carsten Haese <cars...@uniqsys.comwrote:
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'
Sep 7 '07 #3
André wrote:
On Sep 7, 10:27 am, Carsten Haese <cars...@uniqsys.comwrote:
>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:

1. It stops the super-class's __init__() method from being called, and

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.

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 -------------

Sep 7 '07 #4
On Fri, 2007-09-07 at 15:54 +0000, André wrote:
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
[...]
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'
Indeed, if you have an __init__ method that shouldn't see the "group"
argument, you need a metaclass after all so you can yank the "group"
argument between __new__ and __init__. The following code seems to work,
but it's making my brain hurt:

class SplinterBorgMeta(type):
def __call__(cls, *args, **kwargs):
inst = cls.__new__(cls, *args, **kwargs)
kwargs.pop("group",None)
inst.__init__(*args,**kwargs)
return inst

class SplinterBorg(object):
__metaclass__ = SplinterBorgMeta
_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

The alternatives, as Steve just pointed out, would be not to subclass
SplinterBorg or to provide an __init__ method that expects a "group"
argument.

HTH,

--
Carsten Haese
http://informixdb.sourceforge.net
Sep 7 '07 #5
On Sep 7, 3:53 pm, Steve Holden <st...@holdenweb.comwrote:
André wrote:
On Sep 7, 10:27 am, Carsten Haese <cars...@uniqsys.comwrote:
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 -------------

Sep 7 '07 #6
On Sep 7, 4:00 pm, Carsten Haese <cars...@uniqsys.comwrote:
On Fri, 2007-09-07 at 15:54 +0000, André wrote:
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
[...]
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'

Indeed, if you have an __init__ method that shouldn't see the "group"
argument, you need a metaclass after all so you can yank the "group"
argument between __new__ and __init__. The following code seems to work,
but it's making my brain hurt:

class SplinterBorgMeta(type):
def __call__(cls, *args, **kwargs):
inst = cls.__new__(cls, *args, **kwargs)
kwargs.pop("group",None)
inst.__init__(*args,**kwargs)
return inst

class SplinterBorg(object):
__metaclass__ = SplinterBorgMeta
_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

The alternatives, as Steve just pointed out, would be not to subclass
SplinterBorg or to provide an __init__ method that expects a "group"
argument.

HTH,
Thanks for your reply. I will try to adapt it and see if it works in
my case.

André
--
Carsten Haesehttp://informixdb.sourceforge.net

Sep 7 '07 #7
Carsten Haese wrote:
Indeed, if you have an __init__ method that shouldn't see the "group"
argument, you need a metaclass after all so you can yank the "group"
argument between __new__ and __init__. The following code seems to work,
but it's making my brain hurt:

class SplinterBorgMeta(type):
def __call__(cls, *args, **kwargs):
inst = cls.__new__(cls, *args, **kwargs)
kwargs.pop("group",None)
inst.__init__(*args,**kwargs)
return inst

class SplinterBorg(object):
__metaclass__ = SplinterBorgMeta
_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
I think I would probably write that as::
>>class SplinterBorgMeta(type):
... def __init__(cls, name, bases, bodydict):
... cls._shared_states = {}
... def __call__(cls, *args, **kwargs):
... group = kwargs.pop('group', None)
... inst = cls.__new__(cls, *args, **kwargs)
... inst.__dict__ = cls._shared_states.setdefault(group, {})
... inst.__init__(*args, **kwargs)
... return inst
...
>>class MyClass(object):
... __metaclass__ = SplinterBorgMeta
... def __init__(self, name):
... self.name = name
...
>>a = MyClass('a')
aa = MyClass('aa')
b = MyClass('b', group='b')
bb = MyClass('bb', group='b')
a.name, aa.name, b.name, bb.name
('aa', 'aa', 'bb', 'bb')

That is, I don't think there's really a need for __new__ if you're using
a metaclass. Just set the instance's __dict__ in the __call__ method of
the metaclass.

STeVe
Sep 7 '07 #8
On Fri, 2007-09-07 at 14:54 -0600, Steven Bethard wrote:
Carsten Haese wrote:
[slightly convoluted example...]

I think I would probably write that as::
[concise example...]

That is, I don't think there's really a need for __new__ if you're using
a metaclass. Just set the instance's __dict__ in the __call__ method of
the metaclass.
Good point. I suppose it shows that this is the first metaclass I've
ever written, but it works, and it didn't make my brain explode ;)

--
Carsten Haese
http://informixdb.sourceforge.net
Sep 8 '07 #9
On Sep 7, 1:53 pm, Steve Holden <st...@holdenweb.comwrote:
All you really need is to create your SplinterBorgs with appropriate
group names, you don't neef subclasses at all:
Dang. With that subject heading I thought this was about some post-
Singularity, Python-programmed cyborgs rising up to take over the
universe.

See, e.g.
<a href="http://www.amazon.com/How-Survive-Robot-Uprising-Defending/dp/
1582345929/inscape-20">How To Survive A Robot Uprising</a>

I am officially misled!

rd

Sep 8 '07 #10
On Sep 7, 1:53 pm, Steve Holden <st...@holdenweb.comwrote:
All you really need is to create your SplinterBorgs with appropriate
group names, you don't neef subclasses at all:
oops, I tried this once and the link broke. I'll try tinyurl.

Dang. With that subject heading I thought this was about some post-
Singularity, Python-programmed cyborgs rising up to take over the
universe.

See, e.g.
How To Survive A Robot Uprising
http://tinyurl.com/yrk5pw

I am officially misled!

rd
Sep 8 '07 #11

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

Similar topics

5
by: Irmen de Jong | last post by:
Hi, I've developed the Metaclass below, because I needed a way to make a bunch of classes thread-safe. I didn't want to change every method of the class by adding lock.aqcuire()..lock.release()...
33
by: Jacek Generowicz | last post by:
I would like to write a metaclass which would allow me to overload names in the definition of its instances, like this class Foo(object): __metaclass__ = OverloadingClass att = 1 att = 3
6
by: Steven D'Aprano | last post by:
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...
14
by: Pedro Werneck | last post by:
Hi I have a class A, with metaclass M_A, and class B, subclass of A, with metaclass M_B, subclass of M_A. A class C, subclass of B must have M_B or a subclass of it as metaclass, but what if...
0
by: mikelostcause | last post by:
Is there anyway to hold the base.WndProc(ref m) until after the Logout() function finishes loading a webpage?? I'm working on shutting down an app that runs in the system tray, I have no...
1
by: Jake Barnes | last post by:
I searched comp.lang.javascript on Google Groups but I didn't find an answer when I searched for "viewport" or "viewport div" or any combination of words using "viewport" so now I think I'm...
4
by: Chuck B | last post by:
I have a .NET application installed on a server. It runs fine when I run an instance on my PC. My question is, is it possible to run a .NET app hosted on a server without having the framework...
2
by: Chuck B | last post by:
Is it equally possible to create WPF objects for use in a web browser as well as WinForms?
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: DolphinDB | last post by:
The formulas of 101 quantitative trading alphas used by WorldQuant were presented in the paper 101 Formulaic Alphas. However, some formulas are complex, leading to challenges in calculation. Take...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
0
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

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.