strange behavor....

Mark Wooding mdw at distorted.org.uk
Sat Nov 13 17:22:00 EST 2010


Arnaud Delobelle <arnodel at gmail.com> writes:

> mdw at distorted.org.uk (Mark Wooding) writes:
>
> > Assignment /never/ binds.  There is syntactic confusion here too,
> > since Python interprets a simple assignment in a function body -- in
> > the absence of a declaration such as `global' to the contrary -- as
> > indicating that the variable in question should be bound to a fresh
> > variable on entry to the function.  But assignment itself doesn't
> > perform binding.  (This is a persistent error in the Python community;
> > or, less charitably, the Python community gratuitously uses the word
> > in a different sense from the wider programming-language-theory
> > community.  See Lisp literature passim, for example.)
> >
> > There's a two step mapping: names -> storage locations -> values.
> > Binding affects the left hand part of the mapping; assignment affects
> > the right hand part.
>

> I'm not sure the notion of "storage location" is useful in Python.

We'll see.

> I think I understand Python programs correctly using only the notions
> of "name" and "value" (or object).

Challenge: explain the following code using only those concepts.

        def foo():
          l = []
          for i in xrange(10):
            (lambda j: l.append((lambda: i, lambda: j)))(i)
          print [(f(), g()) for f, g in l]

I explain this as follows.

  * Python's `for' loop works by assignment.  The name `i' remains bound
    to the same storage location throughout; this binding is established
    on entry to the function.  Since `i' is not rebound in any function
    lexically enclosed in `foo', every occurrence of `lambda: i' refers
    to this same storage location.  At the end of the loop, this storage
    location contains the value 9.

  * The name `j' is rebound repeatedly: in each iteration of the `for'
    loop, the function `lambda j: ...' is invoked, binding `j' to a
    fresh storage location into which the value of `i' at the time is
    stored.  Since the function `lambda: j' is lexically enclosed within
    this function, the name `j' refers to a different storage location
    in each of these functions, these storage locations are initialized
    with distinct values 0 up to 9, and they are never changed.

  * Therefore each `lambda: i' function, when called after the loop,
    outputs the same value 9; and each `lambda: j' function, when called
    after the loop, outputs a distinct value.

-- [mdw]



More information about the Python-list mailing list