Function decorator that caches function results
Steven D'Aprano
steve at REMOVETHIScyber.com.au
Sun Oct 9 14:06:51 EDT 2005
On Sun, 09 Oct 2005 17:55:16 +0200, Diez B. Roggisch wrote:
>> 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.
>
> You seem to still not getting to it: they aren't supposed to be
> distinguished - a function is a function. But it _can_ have a closure,
> which (shortly spoken) enriches it's local variables lookup.
[penny drops] Now we're getting somewhere... a closure is something
_added_ to a function. So we should talk about functions-without-closures
and functions-with-closures.
> Speaking in
> terms of "is a" could be seen as some inheritance relation.
[penny rises again] Dammit, just when I thought I got it. So a closure is
like a subclass of function? Functions are a higher level classification,
like mammals. There are mammals that are primates (functions that _are_
closures) and mammals that aren't (functions that _aren't_ closures).
> Which
> functions and functions with a closure _could_ have if one wanted to.
> But that is true for other OO-concepts two. See below.
>
>> 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:-
>
>
> <snip>
>
> Nope. You mix things here. spam1 is a function.
Yes.
> spam2 is actually bound
> to the function-object created by do_nothing -
Yes.
> a function that has a closure because it is nested in closefy, and
> accesses variables from its outer lexical scope - thus i needs a
> closure.
Right! So closures are something which functions _have_ -- which is why
Python functions have an attribute called func_closure, which is empty in
functions without closures, and contain a tuple of cells in those with
them.
Now somebody is going to tell me this is an implementation detail and it
isn't true in the general language independent case...
> Part of do_nothing's closure is spam1 (or, better to say, the
> function reference that has been originally bound to spam1 - spam1 is
> just a name).
Yes, I can see that.
> Important is that the closure gets created at runtime, so
> each returned instance of do_nothing has its own. But the original spam1
> implementation is untouched contrary to what you state above. It still
> is teh same thing, and has no closure.
>
> Consider this:
>
> class Foo(object):
> pass
>
> f = Foo()
> g = Foo()
> g.bar = "whatever"
>
> f and g are both Foo
Now you're trying to trick me... they are both *instances* of Foo, not
Foo. Foo is a class, and f and g are not classes, let alone the same class.
> - but one has a different attribute set. And if Foo
> had some semantics that did something different based on bar, would you
> also say they're supposed have two different classes? You could in fact
> do that - create one class for each incarnation of possible state. But
> then the concept of classes and objects gets somewhat blurred, as each
> instance would have its own class. The same is true for functions.
Ah, but in languages like Pascal that can take functions as arguments, but
can't return functions as output, *all* functions have to be created
separately. To take your analogy and run with it, Pascal would be like a
language that didn't allow f and g to have different attributes unless
they belonged to different classes.
Python is not like that, which is why you can write a function to return
functions (a factory function?). If the output function needs access to
the namespace of the factory function, Python adds a closure to that
output function, giving it access to the objects in that namespace.
--
Steven.
More information about the Python-list
mailing list