confused by bindings

Alex Martelli aleax at aleax.it
Fri Sep 21 04:05:25 EDT 2001


"Sam Falkner" <samf+usenet at frii.com> wrote in message
news:ii7elp160go.fsf at central.sun.com...
> Here's what I've found.  I tried four different methods, putting them
> into two modules: work and test.  The four methods:
>
>     (1) Borg class,

I'm going to examine this one only, as it's the one that
specifically deals with Borg.

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

So you're asking for Borg._Borg__shared_state['countone'] to
be reset to 0 each and every time an instance of Borg is
created.  I'm not sure why, but, OK -- this IS what you're
doing here.

> class One:
>     def __init__(self):
>         borg = Borg()
>         borg.countone += 1

And here, each time an instance of One is created, the
shared state 'countoune' of class Borg is first reset
to 0 (by instantiating Borg, see above), then set to 1
(through a specific instance of Borg, but of course by
definition of Borg that doesn't matter).  Then the
specific Borg instance is thrown away, being a local
variable of One.__init__, but that doesn't matter
either.

> def work1():
>     junk = []
>     for i in range(5):
>         junk.append(One())
>     return junk

So you're repeating five times the "set Borg's shared
state "countone" to 1", as well as returning a list of
five (empty) instances of class One.  OK.

> class WorkTestCase(unittest.TestCase):
>     def testOne(self):
>         b = work.Borg()
>         b.countone = 0

This last statement is redundant, of course, since you
already set the 'countone' state of all Borgs to 0 (by
instantiating a Borg) in the previous statement.  Of
course, it's innocuous to repeat this.

>         junk = work.work1()
>         self.failUnlessEqual(len(junk), b.countone)

Now this is the one I really don't understand!  How
could len(junk), which we KNOW is five, POSSIBLY
equal the 'countone' state of all Borgs, which we
KNOW just as well is ONE?!  Since "work1"'s job IS
to set that count to one -- hey, it sets it to one
FIVE TIMES just to make sure...!

I'm starting to suspect that the "self.countone = 0"
second statement of Borg.__init__, which you wrote,
is *NOT* what you actually MEANT to write.  It *IS*
clear to you that, since all Borg instances share
all state (that's the POINT of class Borg!), this is
zeroing out the shared state of 'countone' each time
an instance is created, right?

If your class Borg was totally different, e.g.:

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

THEN there would be no zeroing of the 'countone'
shared-state entry at each Borg instantiation, and
things might work a bit more like you appear to
expect them to (judging by the failUnlessEqual
that we see in WorkTestCase.testOne).

To repeat, that's the POINT of Borg: when you
'bloobet' one of them, you 'bloobet' them all,
where 'bloobet' is any verb having to do with
alteration of and/or access to instance state.

Borg instance have separate _identity_ (id()
builtin function); subclasses of Borg may
give instances with separate _behavior_ (by
adding methods to the subclass-object) and/or
produce strange effects by failing to call
Borg.__init__ in a subclass-specific
initialization (as for other such cases in
Python) or playing dirty tricks with the
_Borg__shared_state class attribute; and
that's about it.


Alex






More information about the Python-list mailing list