This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author ncoghlan
Recipients berker.peksag, ethan.furman, mark.dickinson, ncoghlan, petr.viktorin, yselivanov
Date 2015-04-29.06:40:07
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1430289607.64.0.0364658820841.issue24056@psf.upfronthosting.co.za>
In-reply-to
Content
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
History
Date User Action Args
2015-04-29 06:40:07ncoghlansetrecipients: + ncoghlan, mark.dickinson, petr.viktorin, ethan.furman, berker.peksag, yselivanov
2015-04-29 06:40:07ncoghlansetmessageid: <1430289607.64.0.0364658820841.issue24056@psf.upfronthosting.co.za>
2015-04-29 06:40:07ncoghlanlinkissue24056 messages
2015-04-29 06:40:07ncoghlancreate