> --------------------------------
>  def doLambda(val):
>    print "value 2:", val
>
>  commands = []
>  for value in range(5):
>    print "value 1:", value
>    commands.append(lambda:doLambda(value))
>
>  for c in commands:
>    c()


Hi Fred,

Ah, this one of those unfrequently asked questions.

lambdas in Python's for loop are a little tricky because the for loop
rebinds the element variable.  That is, what's happening is that all those
lambda functions are just resetting the same 'value' variable: the loop is
merely rebinding value to the elements of range(5).  All the lambdas are
sharing the same name binding, and that explains why we see this kind of
aliasing behavior.

One possible fix is to do this:

######
def makeDoLambda(value):
    def f(): return doLambda(value)
    return f
######

Once we have this makeDoLambda() function, then we can use it:

    commands.append(makeDoLambda(value))

The act of calling the makeDoLambda() function makes a fresh name binding
to 'value', so that none of the lambda functions share the same binding.

Another way to do this is to force our lambda to make a fresh binding with
a default parameter:

    commands.append(lambda v=value: doLambda(v))

This is subtle, so if you have more questions, please feel free to ask.





Slightly off-topic footnote: if you're familiar with the Scheme
programming language, then what's happening can be simulated like this:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Simulates some of the essence of Python's for loop
(define-syntax python-for-each
  (syntax-rules ()
    ((_ (id list) e1 e2 ...)
     (let ((id #f))
       (let loop ((L list))
         (if (null? L)
             (void)
             (begin
               (set! id (car L))
               e1 e2 ...
               (loop (cdr L)))))))))

(begin
  (define commands '())
  (python-for-each (i '(1 2 3 4 5))
      (set! commands (cons (lambda () i) commands)))
  (for-each (lambda (f) (display (f)) (newline)) commands))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Python's loop has set!-ish behavior, and it's that rebinding behavior that
causes the issues you are seeing.

_______________________________________________
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor

Reply via email to