diff options
author | Ezio Melotti <ezio.melotti@gmail.com> | 2013-01-04 22:50:46 (GMT) |
---|---|---|
committer | Ezio Melotti <ezio.melotti@gmail.com> | 2013-01-04 22:50:46 (GMT) |
commit | cad8b0ff8edc2dd6437ee1022977358a16f3860e (patch) | |
tree | 24e772e697b1930202552836a86c7d534eff9df6 | |
parent | d73f369f4c52e921ba225043c0a820856369ef44 (diff) | |
download | cpython-cad8b0ff8edc2dd6437ee1022977358a16f3860e.zip cpython-cad8b0ff8edc2dd6437ee1022977358a16f3860e.tar.gz cpython-cad8b0ff8edc2dd6437ee1022977358a16f3860e.tar.bz2 |
#13094: add Programming FAQ entry about the behavior of closures.
-rw-r--r-- | Doc/faq/programming.rst | 52 | ||||
-rw-r--r-- | Misc/NEWS | 3 |
2 files changed, 55 insertions, 0 deletions
diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst index aac8e81..32123de 100644 --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -206,6 +206,58 @@ an imported module. This clutter would defeat the usefulness of the ``global`` declaration for identifying side-effects. +Why do lambdas defined in a loop with different values all return the same result? +---------------------------------------------------------------------------------- + +Assume you use a for loop to define a few different lambdas (or even plain +functions), e.g.:: + + squares = [] + for x in range(5): + squares.append(lambda: x**2) + +This gives you a list that contains 5 lambdas that calculate ``x**2``. You +might expect that, when called, they would return, respectively, ``0``, ``1``, +``4``, ``9``, and ``16``. However, when you actually try you will see that +they all return ``16``:: + + >>> squares[2]() + 16 + >>> squares[4]() + 16 + +This happens because ``x`` is not local to the lambdas, but is defined in +the outer scope, and it is accessed when the lambda is called --- not when it +is defined. At the end of the loop, the value of ``x`` is ``4``, so all the +functions now return ``4**2``, i.e. ``16``. You can also verify this by +changing the value of ``x`` and see how the results of the lambdas change:: + + >>> x = 8 + >>> squares[2]() + 64 + +In order to avoid this, you need to save the values in variables local to the +lambdas, so that they don't rely on the value of the global ``x``:: + + squares = [] + for x in range(5): + squares.append(lambda n=x: n**2) + +Here, ``n=x`` creates a new variable ``n`` local to the lambda and computed +when the lambda is defined so that it has the same value that ``x`` had at +that point in the loop. This means that the value of ``n`` will be ``0`` +in the first lambda, ``1`` in the second, ``2`` in the third, and so on. +Therefore each lambda will now return the correct result:: + + >>> squares[2]() + 4 + >>> squares[4]() + 16 + +Note that this behaviour is not peculiar to lambdas, but applies to regular +functions too. + + How do I share global variables across modules? ------------------------------------------------ @@ -867,6 +867,9 @@ Tools/Demos Documentation ------------- +- Issue #13094: add "Why do lambdas defined in a loop with different values + all return the same result?" programming FAQ. + - Issue #14901: Update portions of the Windows FAQ. Patch by Ashish Nitin Patil. |