How does Mr. Martelli's Borg recipe work ?

Discussion in 'Python' started by Mars, Jul 23, 2003.

  1. Mars

    Mars Guest

    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
    how it works. _shared_state is never assigned any value, only
    self.__dict__ is assigend self._shared_sate's value - or rather
    (self.)_shared_state must be assigned a value at some point, otherwise
    the code wouldn't work(right ?). I have gone through the code in the
    debugger several(many) times, and inserted god knows how many print
    statements, but without luck(or skill i guess).

    Just so you don't waste your time, i do understand that _shared_state
    is a class field(variable, or what not) and that its state is shared
    by all instances.

    Sorry if this question is banal, but I really need to understand this,
    even if it means exposing my complete lack of understanding as far as
    what is probaly basic Python knowledge.

    Regards,

    Martin
     
    Mars, Jul 23, 2003
    #1
    1. Advertising

  2. Mars

    Terry Reedy Guest

    "Mars" <> wrote in message
    news:...
    > 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
    > how it works. _shared_state is never assigned any value, only
    > self.__dict__ is assigend self._shared_sate's value - or rather
    > (self.)_shared_state must be assigned a value at some point,

    otherwise
    > the code wouldn't work(right ?).


    Yes and no. The 'value' of a name is the object it is assigned to.
    In the last line of the 4 line code and only body line of the __init__

    class Borg:
    __shared_state = {}
    def __init__(self):
    self.__dict__ = self.__shared_state

    the instance name '__dict__' is rebound to the object also called
    __shared_state, so that the two names become aliases for the *same*
    object (of type dict). The original instance dict gets unbound from
    the name__dict__ and becomes eligible to be garbage collected. The
    same is true for every Borg instance. Create 100 Borg instances and
    there are 101 aliases for one and the same dict.

    Now ,
    instance.name = value
    is (usually) executed behind the scence as
    instance.__dict__['name'] = value
    where __dict__ is the dict *currently* bound to instance attribute
    __dict__. (One of the exceptions to this is _dict__ itself.) In the
    Borg scheme, that name is no longer bound to the original dict but to
    the shared dict. So nothing is (or at least need be) ever added to
    that dict under its first name of __shared_state.

    Terry J. Reedy
     
    Terry Reedy, Jul 23, 2003
    #2
    1. Advertising

  3. Mars

    Ian Bicking Guest

    On Tue, 2003-07-22 at 20:37, Mars wrote:
    > 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
    > how it works.


    While I don't want to discourage you from learning more about the
    internals of Python objects (certainly a worthwhile goal), "singletons"
    are usually thought about too hard by people new to Python. This is a
    good way to make a singleton:

    class _Something:
    ...

    TheSomething = _Something()


    Then just never refer to _Something again. Import TheSomething (calling
    it whatever you want), and use it, not its class. It's a singleton
    because there's only one of them. Simplicity!

    Ian
     
    Ian Bicking, Jul 23, 2003
    #3
  4. Mars

    Robin Becker Guest

    In article <>, Ian Bicking
    <> writes
    >
    >class _Something:
    > ...
    >
    >TheSomething = _Something()
    >
    >
    >Then just never refer to _Something again. Import TheSomething (calling
    >it whatever you want), and use it, not its class. It's a singleton
    >because there's only one of them. Simplicity!
    >
    > Ian
    >

    .....can't one do
    class TheSomething:
    ....

    TheSomething = TheSomething()

    then it's harder to get at the class which presumably is now only
    available as TheSomething.__class__
    --
    Robin Becker
     
    Robin Becker, Jul 23, 2003
    #4
  5. Robin Becker wrote:

    > ....can't one do
    > class TheSomething:
    > ....
    >
    > TheSomething = TheSomething()
    >
    > then it's harder to get at the class which presumably is now only
    > available as TheSomething.__class__


    Well, you can name the class Hugahglaugahglaugalgha, or delete the
    original class name explicitly, or any such thing. The point is that in
    Python, if you're accessing a name starting with underscores in
    something you don't own, you probably shouldn't be. "We're all adults
    here."

    --
    Erik Max Francis && && http://www.alcyone.com/max/
    __ San Jose, CA, USA && 37 20 N 121 53 W && &tSftDotIotE
    / \ Why place value or judgement on color?
    \__/ Andrew Coler
     
    Erik Max Francis, Jul 23, 2003
    #5
  6. Mars

    Mars Guest

    Thanks guys - as I thought - basic stuff I had gotten wrong.

    Regards,

    Martin
     
    Mars, Jul 23, 2003
    #6
  7. Mars

    Ian Bicking Guest

    On Wed, 2003-07-23 at 02:45, Robin Becker wrote:
    > ....can't one do
    > class TheSomething:
    > ....
    >
    > TheSomething = TheSomething()
    >
    > then it's harder to get at the class which presumably is now only
    > available as TheSomething.__class__


    I wouldn't generally name the class and the singleton the same, but just
    because that is confusing -- if you look briefly at the code you'll
    initially think that TheSomething is a class, when it is actually an
    instance. Better would be:

    class _Something:
    ....

    TheSomething = _Something()
    del _Something

    Ian
     
    Ian Bicking, Jul 23, 2003
    #7
  8. Quoth John Roth:
    [...]
    > I can kind of understand the justification for the Borg pattern
    > in Python releases before 2.2, because there was no way of
    > creating a true singleton in those releases. However, in 2.2 and
    > later, it's really easy to create one using new style classes.

    [...implementing singletons with __new__...]
    > That being the case, I'd like to see the Borg pattern go the way
    > of a fondly remembered hack that is no longer necessary.


    Just out of curiosity: why do you prefer singletons to Borgs in
    the first place?

    (I don't see Borg as a hack to get the behaviour of a singleton; I
    see it as a more direct way to solve the problem which singletons
    are supposed to solve. Thus to me Borg is actually preferable, in
    those exceedingly rare cases when that problem actually arises.)

    --
    Steven Taschuk
    "I may be wrong but I'm positive." -- _Friday_, Robert A. Heinlein
     
    Steven Taschuk, Jul 23, 2003
    #8
  9. On Wed, 23 Jul 2003 12:48:00 -0600, Steven Taschuk <> wrote:

    >Quoth John Roth:
    > [...]
    >> I can kind of understand the justification for the Borg pattern
    >> in Python releases before 2.2, because there was no way of
    >> creating a true singleton in those releases. However, in 2.2 and
    >> later, it's really easy to create one using new style classes.

    > [...implementing singletons with __new__...]
    >> That being the case, I'd like to see the Borg pattern go the way
    >> of a fondly remembered hack that is no longer necessary.

    >
    >Just out of curiosity: why do you prefer singletons to Borgs in
    >the first place?
    >
    >(I don't see Borg as a hack to get the behaviour of a singleton; I
    >see it as a more direct way to solve the problem which singletons
    >are supposed to solve. Thus to me Borg is actually preferable, in
    >those exceedingly rare cases when that problem actually arises.)
    >

    How about just

    import zerolengthfile as borginstancename

    and using it? E.g.,

    [14:04] C:\pywk\clp>dir zer*, a.* b.*
    <snips>
    03-07-23 13:50 0 zero_len.py
    03-07-23 14:01 28 a.py
    03-07-23 14:02 28 b.py

    [14:05] C:\pywk\clp>type a.py
    import zero_len as aborg


    [14:05] C:\pywk\clp>type b.py
    import zero_len as bborg


    [14:05] C:\pywk\clp>python
    Python 2.2.2 (#37, Oct 14 2002, 17:02:34) [MSC 32 bit (Intel)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import zero_len as inter
    >>> import a
    >>> import b
    >>> dir()

    ['__builtins__', '__doc__', '__name__', 'a', 'b', 'inter']
    >>> dir(a)

    ['__builtins__', '__doc__', '__file__', '__name__', 'aborg']
    >>> dir(b)

    ['__builtins__', '__doc__', '__file__', '__name__', 'bborg']
    >>> inter.x = 123
    >>> a.aborg.x

    123
    >>> b.bborg.x

    123
    >>> b.bborg.y = 456
    >>> a.aborg.y

    456
    >>> inter.y

    456
    >>>


    Regards,
    Bengt Richter
     
    Bengt Richter, Jul 23, 2003
    #9
  10. Quoth Bengt Richter:
    [borg vs singleton]
    > How about just
    >
    > import zerolengthfile as borginstancename
    >
    > and using it? E.g., [...]


    That would be fine in many cases, I'm sure.

    Modules don't do properties (or other descriptor magic), though.

    --
    Steven Taschuk 7\ 7'Z {&~ .
    Y r --/hG-
    (__/ )_ 1^1`
     
    Steven Taschuk, Jul 23, 2003
    #10
  11. Mars

    Bob Gailer Guest

    Cookbook idea - single-shot __init__

    I have at times had the need to initialize some things once at the class
    level, and have resorted to techniques like:

    class foo:
    first = True
    def __init__(self):
    if foo.first:
    foo.first = False
    # initialization code

    Then a "better idea" occurred:

    class foo:
    def __init__(self):
    del foo.__init__
    # initialization code

    Bob Gailer

    303 442 2625


    ---
    Outgoing mail is certified Virus Free.
    Checked by AVG anti-virus system (http://www.grisoft.com).
    Version: 6.0.500 / Virus Database: 298 - Release Date: 7/10/2003
     
    Bob Gailer, Jul 24, 2003
    #11
  12. Mars

    Ben Finney Guest

    Re: Cookbook idea - single-shot __init__

    On Wed, 23 Jul 2003 19:15:23 -0600, Bob Gailer wrote:
    > I have at times had the need to initialize some things once at the
    > class level


    In Python 2.2 (earlier?) you can define any attribute at the class
    level, and it will be shared by all instances:

    class Foo( object ):
    grumble = 0.1
    flibble = {}
    def __init__( self ):
    ''' Instance initialisation '''
    return

    This causes the attributes 'grumble', 'flibble', and '__init__()' to be
    shared by all Foo instances; anything done within __init__() will affect
    the individual instance only.

    --
    \ "I stayed up all night playing poker with tarot cards. I got a |
    `\ full house and four people died." -- Steven Wright |
    _o__) |
    http://bignose.squidly.org/ 9CFE12B0 791A4267 887F520C B7AC2E51 BD41714B
     
    Ben Finney, Jul 24, 2003
    #12
  13. On Wed, 23 Jul 2003 16:40:00 -0600, Steven Taschuk <> wrote:

    >Quoth Bengt Richter:
    > [borg vs singleton]
    >> How about just
    >>
    >> import zerolengthfile as borginstancename
    >>
    >> and using it? E.g., [...]

    >
    >That would be fine in many cases, I'm sure.
    >
    >Modules don't do properties (or other descriptor magic), though.
    >

    Not insurmountable ;-)

    ====< propmod.py >==========================================
    class PropModNames(object):
    def __get__(self, ob, cls=None):
    if ob is None: return self
    return 'Shared names of propmod: %r' % vars(ob).keys()
    def __set__(self, ob, val): raise AttributeError, 'names property is read-only'
    def __delete__(self, ob, val): raise AttributeError, 'names property is read-only'

    class SetPropModProp(object):
    def __init__(self): self.name2use = None
    def __get__(self, ob, cls=None):
    if ob is None: return self
    if not self.name2use:
    props = [k for k,v in vars(ob.__class__).items()
    if not k.startswith('_') and (
    hasattr(v, '__get__') or hasattr(v, '__set__'))]
    props.sort()
    return 'Properties of propmod: %r' % props
    else:
    return getattr(ob.__class__, self.name2use)
    def __set__(self, ob, nameNprop):
    if isinstance(nameNprop,str): self.name2use = nameNprop
    elif len(nameNprop)==1: delattr(ob.__class__, nameNprop[0]) # (name,) means delete
    else: name, prop = nameNprop; setattr(ob.__class__, name, prop)

    class PropMod(object):
    names = PropModNames()
    properties = SetPropModProp() # expects propmod.setprop = name, property or name2use
    def __init__(self): __import__('sys').modules['propmod'] = self
    ============================================================

    ===< apm.py >============
    import propmod as zz
    =========================

    The first lines below binds the real propmod module temporarily.
    The second line binds the magic propmod locally and makes it available
    (by PropMod.__init__ side effect ) for import by anyone else as
    an ordinary (looking) "import propmod." (Note what apm.py does).

    I thought it cute to make a property that is a kind of gateway to
    the class attribute space, so that one can use the .properties attribute
    of the propmod module to list, store, retrieve, and delete properties -- as well
    as arbitrary class variables...

    >>> import propmod
    >>> propmod = propmod.PropMod()
    >>> propmod.properties

    "Properties of propmod: ['names', 'properties']"
    >>> propmod.names

    'Shared names of propmod: []'
    >>> propmod.x = 123
    >>> propmod.y = 456
    >>> propmod.names

    "Shared names of propmod: ['y', 'x']"
    >>> propmod.properties

    "Properties of propmod: ['names', 'properties']"
    >>> propmod.properties = ('hello', property(lambda self:'Hello properties!'))
    >>> propmod.properties

    "Properties of propmod: ['hello', 'names', 'properties']"
    >>> propmod.hello

    'Hello properties!'
    >>> import apm
    >>> apm.zz.properties

    "Properties of propmod: ['hello', 'names', 'properties']"
    >>> apm.zz.hello

    'Hello properties!'
    >>> apm.zz.z = 'z via apm.zz.z'
    >>> propmod.z

    'z via apm.zz.z'
    >>> apm.zz.names

    "Shared names of propmod: ['y', 'x', 'z']"

    Not to go on and on, but ...

    >>> apm.zz.properties = ('hello',)
    >>> propmod.properties

    "Properties of propmod: ['names', 'properties']"
    >>> propmod.properties = 'names'
    >>> propmod.properties

    <propmod.PropModNames object at 0x007E01F0>
    >>> propmod.properties = ''
    >>> propmod.properties

    "Properties of propmod: ['names', 'properties']"
    >>> propmod.properties = ('classvar', 'classvar value')
    >>> apm.zz.properties

    "Properties of propmod: ['names', 'properties']"
    >>> apm.zz.classvar

    'classvar value'
    >>> apm.zz.__class__

    <class 'propmod.PropMod'>
    >>> apm.zz.__class__.__dict__.keys()

    ['__module__', 'names', '__dict__', 'classvar', '__weakref__', 'properties', '__init__', '__doc__']
    >>> apm.zz.__class__.__dict__['classvar']

    'classvar value'
    >>> apm.zz.classvar = 'obj attr'
    >>> propmod.names

    "Shared names of propmod: ['y', 'x', 'z', 'classvar']"
    >>> propmod.classvar

    'obj attr'
    >>> del propmod.classvar
    >>> propmod.classvar

    'classvar value'

    Regards,
    Bengt Richter
     
    Bengt Richter, Jul 24, 2003
    #13
  14. On 24 Jul 2003 02:47:02 GMT, (Bengt Richter) wrote:

    >On Wed, 23 Jul 2003 16:40:00 -0600, Steven Taschuk <> wrote:
    >
    >>Quoth Bengt Richter:
    >> [borg vs singleton]
    >>> How about just
    >>>
    >>> import zerolengthfile as borginstancename
    >>>
    >>> and using it? E.g., [...]

    >>
    >>That would be fine in many cases, I'm sure.
    >>
    >>Modules don't do properties (or other descriptor magic), though.
    >>

    >Not insurmountable ;-)
    >
    >====< propmod.py >==========================================

    [...]
    >I thought it cute to make a property that is a kind of gateway to
    >the class attribute space, so that one can use the .properties attribute
    >of the propmod module to list, store, retrieve, and delete properties -- as well
    >as arbitrary class variables...


    Of course,

    propmod.__class__.xxx = yyy

    works as well as

    propmod.properties = 'xxx', yyy

    so it's kind of a silly exercise, but it does demo properties for a sharable "module."

    A much sparer approach:

    >>> import sys
    >>> sys.modules['simple'] = type('SimpleMod',(),{})()
    >>> import simple
    >>> simple.x = 123
    >>> simple.__class__.hi = property(lambda self:'Hi ho')
    >>> simple.x

    123
    >>> simple.hi

    'Hi ho'
    >>> file('impsimp.py','w').write('import simple as m\n')
    >>> import impsimp
    >>> impsimp.m.hi

    'Hi ho'
    >>> impsimp.m.x

    123

    Regards,
    Bengt Richter
     
    Bengt Richter, Jul 24, 2003
    #14
  15. Mars

    Ian Bicking Guest

    Re: Cookbook idea - single-shot __init__

    On Wed, 2003-07-23 at 21:17, Ben Finney wrote:
    > On Wed, 23 Jul 2003 19:15:23 -0600, Bob Gailer wrote:
    > > I have at times had the need to initialize some things once at the
    > > class level

    >
    > In Python 2.2 (earlier?) you can define any attribute at the class
    > level, and it will be shared by all instances:


    This is true in all versions of Python. However, there are some
    instances where you can't initialize the attributes at class creation
    time, and you want to delay initializing those variables until some
    later time. This usually is a problem of circular dependencies, or
    where initialization somehow depends on the overall context of the
    program (like configuration variables that may not be fully read by the
    time the module is imported).

    Ian
     
    Ian Bicking, Jul 24, 2003
    #15
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Dave Benjamin

    Alex Martelli: Welcome back!

    Dave Benjamin, Aug 27, 2004, in forum: Python
    Replies:
    3
    Views:
    406
    Alex Martelli
    Aug 27, 2004
  2. Batista, Facundo

    RE: Alex Martelli: Welcome back!

    Batista, Facundo, Aug 27, 2004, in forum: Python
    Replies:
    4
    Views:
    384
    Paul Rubin
    Aug 28, 2004
  3. Michael Sparks

    Re: Alex Martelli: Welcome back!

    Michael Sparks, Aug 27, 2004, in forum: Python
    Replies:
    1
    Views:
    515
    Dave Benjamin
    Aug 27, 2004
  4. Delaney, Timothy C (Timothy)

    RE: Alex Martelli: Welcome back!

    Delaney, Timothy C (Timothy), Aug 30, 2004, in forum: Python
    Replies:
    1
    Views:
    487
    Alex Martelli
    Aug 30, 2004
  5. io
    Replies:
    24
    Views:
    283
    Tad McClellan
    Feb 14, 2006
Loading...

Share This Page