Python 2.0

Jeremy Hylton jeremy at cnri.reston.va.us
Mon Jun 7 15:57:17 EDT 1999


>>>>> "DS" == Dan Schmidt <dfan at harmonixmusic.com> writes:

  DS> Hrvoje Niksic <hniksic at srce.hr> writes: | Kumar Balachandran
  DS> <kumar*xspam*@*xspam*rtp.ericsson.se> writes: | | > What you
  DS> said is quite wrong. Since Python provides closures, I can | >
  DS> change my programming style to be completely different from the
  DS> | > standard C or Fortran style and use a functional interface.
  DS> | | Since when does Python provide closures?

  DS> The bytecodehacks module allows the creation of closures as I
  DS> understand them.

Yes and no.  The bytecodehacks closures work right most of the time,
but there some problems with them.  Hence, I would guess, the name
"hacks."  A "BCH closure" does what you want most of the time, but it
does not work for immutable types or for assignments to mutable types.

The Scheme world view has a different world view, and a closure in
Scheme works a bit differently.  I suspect it may be a little
confusing for people expect BCH to make Python's variable binding work 
like Scheme's variable binding.  In Scheme, a variable is bound to a
location that stores a value.  You can store a new value in that
location using set!.  If two different functions share the same
binding for a variable, a set! performed in one function is visible in 
the other.

>>> (let ((sum 0))
       (let ((add (lambda (x) (set! sum (+ sum x))))
             (sub (lambda (x) (set! sum (- sum x)))))
                (add 2)
                (add 3)
                (sub 1)
             sum))
4

The BCH model is different, because it doesn't allow two functions to
share the same "location."  It only allows them to share the same
value.  This is a limitation of the way BCH implements closures;
non-local references are turned into references to constants when the
bind call is made.  This approach often works the constant is an
object and you're referencing one of its attributes or calling a
method.  It doesn't work for assignment.

The natural translation of the above Scheme code in Python+BCH would
probably be:
from bytecodehacks import closure

def notQuite():
    sum = 0
    def add(x):
        sum = sum + x
    def sub(x):
        sum = sum - x
    cadd = closure.bind_locals(add)
    csub = closure.bind_locals(sub)
    cadd(2)
    cadd(3)
    csub(1)
    return sum

But this doesn't work.  You need to bind sum to a mutable object (not
a string or tuple) and that operator on that object indirectly.  The
following works because it contains the value of interest inside a
list (and list operations are methods on the list object).
Effectively, you need to create the shared location that Scheme
creates for free.

def works():
    sum = [0]
    def add(x):
        sum[0] = sum[0] + x
    def sub(x):
        sum[0] = sum[0] - x
    cadd = closure.bind_locals(add)
    csub = closure.bind_locals(sub)
    cadd(2)
    cadd(3)
    csub(1)
    return sum[0]

Jeremy




More information about the Python-list mailing list