Message242214
It's mostly pedagogical - similar to "normal functions" vs "generator functions", folks talk about functions and closures as different things, even though in Python a closure is just a normal function with one or more references to cells that were defined in outer scopes.
Having that show up in the repr() then becomes a way of clarifying that some, but not all, Python function objects are closures, even though closures aren't represented as a distinct type.
That difference also shows up in the bytecode that creates them (note the MAKE_FUNCTION vs MAKE_CLOSURE):
>>> def outer():
... x = 1
... def inner_function():
... pass
... def inner_closure():
... return x
...
>>> import dis
>>> dis.dis(outer)
2 0 LOAD_CONST 1 (1)
3 STORE_DEREF 0 (x)
3 6 LOAD_CONST 2 (<code object inner_function at 0x7fade75e5c90, file "<stdin>", line 3>)
9 LOAD_CONST 3 ('outer.<locals>.inner_function')
12 MAKE_FUNCTION 0
15 STORE_FAST 0 (inner_function)
5 18 LOAD_CLOSURE 0 (x)
21 BUILD_TUPLE 1
24 LOAD_CONST 4 (<code object inner_closure at 0x7fade75e5a50, file "<stdin>", line 5>)
27 LOAD_CONST 5 ('outer.<locals>.inner_closure')
30 MAKE_CLOSURE 0
33 STORE_FAST 1 (inner_closure)
36 LOAD_CONST 0 (None)
39 RETURN_VALUE
One particular case where the distinction matters and is known to be genuinely confusing for new Python users is the late binding behaviour of closures:
lambda: i # closure
lambda i=i: i # not a closure |
|
Date |
User |
Action |
Args |
2015-04-29 06:40:07 | ncoghlan | set | recipients:
+ ncoghlan, mark.dickinson, petr.viktorin, ethan.furman, berker.peksag, yselivanov |
2015-04-29 06:40:07 | ncoghlan | set | messageid: <1430289607.64.0.0364658820841.issue24056@psf.upfronthosting.co.za> |
2015-04-29 06:40:07 | ncoghlan | link | issue24056 messages |
2015-04-29 06:40:07 | ncoghlan | create | |
|