S
Steven D'Aprano
given that the wikipedia page says
"a closure is an abstraction representing a function, plus the
lexical environment (see static scoping) in which the function
was created."
and you're still focussing on type(function), it sure looks as if you missed
certain parts of that explanation.
let's take it again, with emphasis on some important words:
"a closure is an ABSTRACTION representing a function, PLUS the
lexical ENVIRONMENT (see static scoping) in which the function
was created."
that's because "closure" is an abstract concept.
So are functions, modules, classes, instances, ints and strings.
there is no "closure" object
in Python, just as there is no "program" object.
Clearly there is no DISTINCT closure object. If there were, I wouldn't
need to ask how one can tell them apart, because type() would just report
that one was a function and one was a closure. I don't have a problem with
that. But read on...
function objects always con-
tain all the information they need about their context, and the sum of that is
what forms the closure.
If what you say is true, then all functions are closures, and closure is
just a synonym for function, and there is no difference between a function
and a closure. Then why bother to create the term? Clearly, whoever
invented the term did so to distinguish the two.
At a practical, Python level, there is a difference between a function
before and after it gets made into a closure using, e.g. the original
poster's memoization technique. In Python at least, it is not true that a
function and a function-turned-into-closure is the same thing.
See, for example, this:-
.... def do_nothing(*args, **kwargs):
.... return fn(*args, **kwargs)
.... return do_nothing
........ return 0
....'0xf6e0a144'
In one case, the "raw" function has None stored in its func_closure
attribute. In the other, it has a tuple containing at least one object of
type cell. That cell object appears to contain a reference back to the
original "raw" function.
Now, I'll tell you what I think is going on: spam1() obviously has lexical
scope, but that scope doesn't need to be saved with the function because
it is implicitly understood by Python.
The output of closefy(), on the other hand, has scope different from
the "normal" Python scope. So its output has to package up enough
information to re-create it's lexical scope in a cell object, and
that gets stored in the output's func_closure attribute.
So no, there is no "abstract" difference between a closure and a raw
function, but there is a practical difference. Now perhaps in some other
languages there is no practical difference either, but (as far as I can
see) Python is not that language.
Am I close?
Here are another two code snippets that show something of what Python is
doing:-
.... def shrubbery():
.... return 0
.... return shrubbery
....
.... n = 0True
.... def shrubbery():
.... return n
.... return shrubbery
....(<cell at 0xf70a2b24: int object at 0x901a158>,)