How does Mr. Martelli's Borg recipe work ?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Mars

    How does Mr. Martelli's Borg recipe work ?

    I have looked long and hard at Mr. Martelli's Borg recipe:



    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_sa te'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
  • Terry Reedy

    #2
    Re: How does Mr. Martelli's Borg recipe work ?


    "Mars" <martin_a_claus en@hotmail.com> wrote in message
    news:764b8294.0 307221520.18017 b09@posting.goo gle.com...[color=blue]
    > I have looked long and hard at Mr. Martelli's Borg recipe:
    >
    > http://aspn.activestate.com/ASPN/Coo...n/Recipe/66531
    >
    > It is a very useful substitute for a Singleton, but I can't figure[/color]
    out[color=blue]
    > how it works. _shared_state is never assigned any value, only
    > self.__dict__ is assigend self._shared_sa te's value - or rather
    > (self.)_shared_ state must be assigned a value at some point,[/color]
    otherwise[color=blue]
    > the code wouldn't work(right ?).[/color]

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

    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


    Comment

    • Ian Bicking

      #3
      Re: How does Mr. Martelli's Borg recipe work ?

      On Tue, 2003-07-22 at 20:37, Mars wrote:[color=blue]
      > I have looked long and hard at Mr. Martelli's Borg recipe:
      >
      > http://aspn.activestate.com/ASPN/Coo...n/Recipe/66531
      >
      > It is a very useful substitute for a Singleton, but I can't figure out
      > how it works.[/color]

      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



      Comment

      • Robin Becker

        #4
        Re: How does Mr. Martelli's Borg recipe work ?

        In article <mailman.105893 0376.7219.pytho n-list@python.org >, Ian Bicking
        <ianb@colorstud y.com> writes[color=blue]
        >
        >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
        >[/color]
        .....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

        Comment

        • Erik Max Francis

          #5
          Re: How does Mr. Martelli's Borg recipe work ?

          Robin Becker wrote:
          [color=blue]
          > ....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__[/color]

          Well, you can name the class Hugahglaugahgla ugalgha, 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 && max@alcyone.com && 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

          Comment

          • Mars

            #6
            Re: How does Mr. Martelli's Borg recipe work ?

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

            Regards,

            Martin

            Comment

            • Ian Bicking

              #7
              Re: How does Mr. Martelli's Borg recipe work ?

              On Wed, 2003-07-23 at 02:45, Robin Becker wrote:[color=blue]
              > ....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__[/color]

              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



              Comment

              • Steven Taschuk

                #8
                Re: How does Mr. Martelli's Borg recipe work ?

                Quoth John Roth:
                [...][color=blue]
                > 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.[/color]
                [...implementing singletons with __new__...][color=blue]
                > 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.[/color]

                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 staschuk@telusp lanet.net
                "I may be wrong but I'm positive." -- _Friday_, Robert A. Heinlein

                Comment

                • Bengt Richter

                  #9
                  Re: How does Mr. Martelli's Borg recipe work ?

                  On Wed, 23 Jul 2003 12:48:00 -0600, Steven Taschuk <staschuk@telus planet.net> wrote:
                  [color=blue]
                  >Quoth John Roth:
                  > [...][color=green]
                  >> 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.[/color]
                  > [...implementing singletons with __new__...][color=green]
                  >> 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.[/color]
                  >
                  >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.)
                  >[/color]
                  How about just

                  import zerolengthfile as borginstancenam e

                  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>typ e a.py
                  import zero_len as aborg


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


                  [14:05] C:\pywk\clp>pyt hon
                  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.[color=blue][color=green][color=darkred]
                  >>> import zero_len as inter
                  >>> import a
                  >>> import b
                  >>> dir()[/color][/color][/color]
                  ['__builtins__', '__doc__', '__name__', 'a', 'b', 'inter'][color=blue][color=green][color=darkred]
                  >>> dir(a)[/color][/color][/color]
                  ['__builtins__', '__doc__', '__file__', '__name__', 'aborg'][color=blue][color=green][color=darkred]
                  >>> dir(b)[/color][/color][/color]
                  ['__builtins__', '__doc__', '__file__', '__name__', 'bborg'][color=blue][color=green][color=darkred]
                  >>> inter.x = 123
                  >>> a.aborg.x[/color][/color][/color]
                  123[color=blue][color=green][color=darkred]
                  >>> b.bborg.x[/color][/color][/color]
                  123[color=blue][color=green][color=darkred]
                  >>> b.bborg.y = 456
                  >>> a.aborg.y[/color][/color][/color]
                  456[color=blue][color=green][color=darkred]
                  >>> inter.y[/color][/color][/color]
                  456[color=blue][color=green][color=darkred]
                  >>>[/color][/color][/color]

                  Regards,
                  Bengt Richter

                  Comment

                  • Steven Taschuk

                    #10
                    Re: How does Mr. Martelli's Borg recipe work ?

                    Quoth Bengt Richter:
                    [borg vs singleton][color=blue]
                    > How about just
                    >
                    > import zerolengthfile as borginstancenam e
                    >
                    > and using it? E.g., [...][/color]

                    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 {&~ .
                    staschuk@telusp lanet.net Y r --/hG-
                    (__/ )_ 1^1`

                    Comment

                    • Bob Gailer

                      #11
                      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
                      bgailer@alum.rp i.edu
                      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

                      Comment

                      • Ben Finney

                        #12
                        Re: Cookbook idea - single-shot __init__

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

                        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

                        Comment

                        • Bengt Richter

                          #13
                          Re: How does Mr. Martelli's Borg recipe work ?

                          On Wed, 23 Jul 2003 16:40:00 -0600, Steven Taschuk <staschuk@telus planet.net> wrote:
                          [color=blue]
                          >Quoth Bengt Richter:
                          > [borg vs singleton][color=green]
                          >> How about just
                          >>
                          >> import zerolengthfile as borginstancenam e
                          >>
                          >> and using it? E.g., [...][/color]
                          >
                          >That would be fine in many cases, I'm sure.
                          >
                          >Modules don't do properties (or other descriptor magic), though.
                          >[/color]
                          Not insurmountable ;-)

                          ====< propmod.py >============== =============== =============
                          class PropModNames(ob ject):
                          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.__cl ass__, self.name2use)
                          def __set__(self, ob, nameNprop):
                          if isinstance(name Nprop,str): self.name2use = nameNprop
                          elif len(nameNprop)= =1: delattr(ob.__cl ass__, nameNprop[0]) # (name,) means delete
                          else: name, prop = nameNprop; setattr(ob.__cl ass__, 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...
                          [color=blue][color=green][color=darkred]
                          >>> import propmod
                          >>> propmod = propmod.PropMod ()
                          >>> propmod.propert ies[/color][/color][/color]
                          "Properties of propmod: ['names', 'properties']"[color=blue][color=green][color=darkred]
                          >>> propmod.names[/color][/color][/color]
                          'Shared names of propmod: []'[color=blue][color=green][color=darkred]
                          >>> propmod.x = 123
                          >>> propmod.y = 456
                          >>> propmod.names[/color][/color][/color]
                          "Shared names of propmod: ['y', 'x']"[color=blue][color=green][color=darkred]
                          >>> propmod.propert ies[/color][/color][/color]
                          "Properties of propmod: ['names', 'properties']"[color=blue][color=green][color=darkred]
                          >>> propmod.propert ies = ('hello', property(lambda self:'Hello properties!'))
                          >>> propmod.propert ies[/color][/color][/color]
                          "Properties of propmod: ['hello', 'names', 'properties']"[color=blue][color=green][color=darkred]
                          >>> propmod.hello[/color][/color][/color]
                          'Hello properties!'[color=blue][color=green][color=darkred]
                          >>> import apm
                          >>> apm.zz.properti es[/color][/color][/color]
                          "Properties of propmod: ['hello', 'names', 'properties']"[color=blue][color=green][color=darkred]
                          >>> apm.zz.hello[/color][/color][/color]
                          'Hello properties!'[color=blue][color=green][color=darkred]
                          >>> apm.zz.z = 'z via apm.zz.z'
                          >>> propmod.z[/color][/color][/color]
                          'z via apm.zz.z'[color=blue][color=green][color=darkred]
                          >>> apm.zz.names[/color][/color][/color]
                          "Shared names of propmod: ['y', 'x', 'z']"

                          Not to go on and on, but ...
                          [color=blue][color=green][color=darkred]
                          >>> apm.zz.properti es = ('hello',)
                          >>> propmod.propert ies[/color][/color][/color]
                          "Properties of propmod: ['names', 'properties']"[color=blue][color=green][color=darkred]
                          >>> propmod.propert ies = 'names'
                          >>> propmod.propert ies[/color][/color][/color]
                          <propmod.PropMo dNames object at 0x007E01F0>[color=blue][color=green][color=darkred]
                          >>> propmod.propert ies = ''
                          >>> propmod.propert ies[/color][/color][/color]
                          "Properties of propmod: ['names', 'properties']"[color=blue][color=green][color=darkred]
                          >>> propmod.propert ies = ('classvar', 'classvar value')
                          >>> apm.zz.properti es[/color][/color][/color]
                          "Properties of propmod: ['names', 'properties']"[color=blue][color=green][color=darkred]
                          >>> apm.zz.classvar[/color][/color][/color]
                          'classvar value'[color=blue][color=green][color=darkred]
                          >>> apm.zz.__class_ _[/color][/color][/color]
                          <class 'propmod.PropMo d'>[color=blue][color=green][color=darkred]
                          >>> apm.zz.__class_ _.__dict__.keys ()[/color][/color][/color]
                          ['__module__', 'names', '__dict__', 'classvar', '__weakref__', 'properties', '__init__', '__doc__'][color=blue][color=green][color=darkred]
                          >>> apm.zz.__class_ _.__dict__['classvar'][/color][/color][/color]
                          'classvar value'[color=blue][color=green][color=darkred]
                          >>> apm.zz.classvar = 'obj attr'
                          >>> propmod.names[/color][/color][/color]
                          "Shared names of propmod: ['y', 'x', 'z', 'classvar']"[color=blue][color=green][color=darkred]
                          >>> propmod.classva r[/color][/color][/color]
                          'obj attr'[color=blue][color=green][color=darkred]
                          >>> del propmod.classva r
                          >>> propmod.classva r[/color][/color][/color]
                          'classvar value'

                          Regards,
                          Bengt Richter

                          Comment

                          • Bengt Richter

                            #14
                            Re: How does Mr. Martelli's Borg recipe work ?

                            On 24 Jul 2003 02:47:02 GMT, bokr@oz.net (Bengt Richter) wrote:
                            [color=blue]
                            >On Wed, 23 Jul 2003 16:40:00 -0600, Steven Taschuk <staschuk@telus planet.net> wrote:
                            >[color=green]
                            >>Quoth Bengt Richter:
                            >> [borg vs singleton][color=darkred]
                            >>> How about just
                            >>>
                            >>> import zerolengthfile as borginstancenam e
                            >>>
                            >>> and using it? E.g., [...][/color]
                            >>
                            >>That would be fine in many cases, I'm sure.
                            >>
                            >>Modules don't do properties (or other descriptor magic), though.
                            >>[/color]
                            >Not insurmountable ;-)
                            >
                            >====< propmod.py >============== =============== =============[/color]
                            [...][color=blue]
                            >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...[/color]

                            Of course,

                            propmod.__class __.xxx = yyy

                            works as well as

                            propmod.propert ies = 'xxx', yyy

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

                            A much sparer approach:
                            [color=blue][color=green][color=darkred]
                            >>> import sys
                            >>> sys.modules['simple'] = type('SimpleMod ',(),{})()
                            >>> import simple
                            >>> simple.x = 123
                            >>> simple.__class_ _.hi = property(lambda self:'Hi ho')
                            >>> simple.x[/color][/color][/color]
                            123[color=blue][color=green][color=darkred]
                            >>> simple.hi[/color][/color][/color]
                            'Hi ho'[color=blue][color=green][color=darkred]
                            >>> file('impsimp.p y','w').write(' import simple as m\n')
                            >>> import impsimp
                            >>> impsimp.m.hi[/color][/color][/color]
                            'Hi ho'[color=blue][color=green][color=darkred]
                            >>> impsimp.m.x[/color][/color][/color]
                            123

                            Regards,
                            Bengt Richter

                            Comment

                            • Ian Bicking

                              #15
                              Re: Cookbook idea - single-shot __init__

                              On Wed, 2003-07-23 at 21:17, Ben Finney wrote:[color=blue]
                              > On Wed, 23 Jul 2003 19:15:23 -0600, Bob Gailer wrote:[color=green]
                              > > I have at times had the need to initialize some things once at the
                              > > class level[/color]
                              >
                              > In Python 2.2 (earlier?) you can define any attribute at the class
                              > level, and it will be shared by all instances:[/color]

                              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



                              Comment

                              Working...