0

I've got the following examples:

  1. outer is a variable defined outside the lambda. Changes to outer are seen by the lambda:
foo = lambda: outer
outer = 'outer'
print(outer) # 'outer'
print(foo()) # 'outer'

outer = 'changed'
print(outer) # 'changed'
print(foo()) # 'changed'
  1. outer is still a variable defined outside the lambda. Changes to outer are still seen by the lambda, but if the change to outer is inside the lambda, then the change to outer is not seen by the outside scope:
foo = lambda: (outer := 'changed in lambda', print(outer))
outer = 'outer'
print(outer) # 'outer'
print(foo()) # 'changed in lambda'
print(outer) # 'outer'
  1. The following are examples of when lambda's do and don't change an outer scope variable. Each example has a def function equivalent (with one caveat) which is also shown:
+---------+-----------------------------------------------+--------------------------------------+------------------------+
| Example | `lambda` version                              | `def` version                        |    change of `outer`   |
|         |                                               |                                      | seen by outside scope? |
+=========+===============================================+======================================+========================+
|   3a.   | ```                                           | ```                                  |           no           |
|         | foo = lambda: \                               | def foo():                           |                        |
|         |   (outer := 'changed in lambda',              |   outer = 'changed in lambda'        |                        |
|         |   print(outer))                               |   print(outer)                       |                        |
|         | outer = 'outer'                               | outer = 'outer'                      |                        |
|         |                                               |                                      |                        |
|         | print(outer) # 'outer'                        | print(outer) # 'outer'               |                        |
|         | foo() # 'changed in lambda'                   | foo() # 'changed in lambda'          |                        |
|         | print(outer) # 'outer'                        | print(outer) # 'outer'               |                        |
|         | ```                                           | ```                                  |                        |
+---------+-----------------------------------------------+--------------------------------------+------------------------+
|   3b.   | no `lambda` version because                   | ```                                  |           yes          |
|         | using `global` in a `lambda`                  | def foo():                           |                        |
|         | seems to be invalid syntax.                   |   global outer                       |                        |
|         |                                               |   outer = 'changed in lambda'        |                        |
|         |                                               |   print(outer)                       |                        |
|         |                                               | outer = 'outer'                      |                        |
|         |                                               |                                      |                        |
|         |                                               | print(outer) # 'outer'               |                        |
|         |                                               | foo() # 'changed in lambda'          |                        |
|         |                                               | print(outer) # 'changed in lambda'   |                        |
|         |                                               | ```                                  |                        |
+---------+-----------------------------------------------+--------------------------------------+------------------------+
|   3c.   | ```                                           | ```                                  |            no          |
|         | foo = lambda: \                               | def foo():                           |                        |
|         |   (outer := ['changed in lambda'],            |   outer = ['changed in lambda']      |                        |
|         |   print(outer))                               |   print(outer)                       |                        |
|         | outer = ['outer']                             | outer = ['outer']                    |                        |
|         |                                               |                                      |                        |
|         | print(outer) # ['outer']                      | print(outer) # ['outer']             |                        |
|         | foo() # ['changed in lambda']                 | foo() # ['changed in lambda']        |                        |
|         | print(outer) # ['outer']                      | print(outer) # ['outer']             |                        |
|         | ```                                           | ```                                  |                        |
+---------+-----------------------------------------------+--------------------------------------+------------------------+
|   3d.   | ```                                           | ```                                  |           yes          |
|         | foo = lambda: \                               | def foo()                            |                        |
|         |   (outer.__setitem__(0, 'changed in lambda'), |   outer[0] = 'changed in lambda'     |                        |
|         |   print(outer))                               |   print(outer)                       |                        |
|         | outer = ['outer']                             | outer = ['outer']                    |                        |
|         |                                               |                                      |                        |
|         | print(outer) # ['outer']                      | print(outer) # ['outer']             |                        |
|         | foo() # ['changed in lambda']                 | foo() # ['changed in lambda']        |                        |
|         | print(outer) # ['changed in lambda']          | print(outer) # ['changed in lambda'] |                        |
|         | ```                                           | ```                                  |                        |
+---------+-----------------------------------------------+--------------------------------------+------------------------+

Table created using https://www.tablesgenerator.com/text_tables


Where can I learn more about the mechanics of lambdas and their scope?

Python doc's definition of lambda goes some ways towards explaining this behavior (emphasis mine):

An anonymous inline function consisting of a single expression which is evaluated when the function is called. The syntax to create a lambda function is lambda [parameters]: expression

joseville
  • 685
  • 3
  • 16
  • 2
    Well, the TL;DR is that `:=` simply always assigns to a local variable inside the function and does not modify the outer variable. To modify the outer variable, you'd need to explicitly declare `global outer`, which is, as you say, invalid inside a lambda since it's a statement, and a lambda only takes an expression. – deceze Oct 13 '21 at 11:28
  • 4
    There is nothing specific to lambdas compared to normal functions, so the normal rules about local variables apply. – Thierry Lathuille Oct 13 '21 at 11:28

0 Answers0