Modifying func_closure

Jacek Generowicz jacek.generowicz at cern.ch
Sun Jul 11 04:30:37 EDT 2004


On 11 Jul 2004, at 06:17, Robert Brewer wrote:

> I asked:
>> Which immediately brings up the question: why not use a
>> class instead?
>
> to which Jacek replied:
>> a) The closure is faster, and my inner loops consist almost
>> entirely of them.
>>
>> b) The closure is much clearer, shorter and more convenient.
>> I have so many of these things that using the class version
>> would make the code a real mess.
>>
>> c) The closure can be stuck on to a class, and works as a
>> method (bound & unbound and all that).
>>
>> d) The outer function which creates the closure can be a method
>> of a class.
>>
>> Probably quite a few more ...
>
> I have to wonder about 'b'; does anyone have an example where a 
> closure is clearer?

Well, I guess that you can't argue with it being shorter and more 
convenient: with the closure you do away with the constructor (in which 
you explicitly enclose the variables you need), and you don't need to 
use "self" to refer to the enclosed variables in the closure itself. If 
you have only one closure, referring to the state, then the class-based 
version can use __call__ to simulate function-call syntax, but if the 
state is shared between more than one closure, you need to prepend 
calls with some instance name. All this is just simple fact: the 
closure version is more concise.

Whether it's clearer, is, of course, a matter of opinion. If Python 
formed your programming mind, and you believe in the third line of the 
Zen of Python to the extreme, then you will probably find the 
class-based version clearer; if you are comfortable with lexical 
scoping, then you will probably find the closure clearer.

Personally, I (would) find it annoying to have to install the plumbing 
myself every time. In the application I'm writing at the moment, I have 
many functions which generate other functions. When I need the 
generated function to have some state, it requires exactly zero extra 
effort on my part: I merely refer to the variable just like any other, 
and it works. If I had to use the class, I would need to rewrite the 
code, add the plumbing, the generated function would require extra work 
before it could be used as a method (and it's impossible before Python 
2.3[*]), and I wouldn't be able to generate it in methods of a class. 
Sorry, I'm not going to come up with code samples showing that the 
closure is clearer, because the class-based version is (to me) so 
inconvenient that I just can't be bothered to even try to make it work 
in the interesting situations.

>  Yes, this means you have to invent syntax to mutate the cell variable 
> if you want to discuss it. ;) Having perused previous discussions, I 
> think I'm favoring the 'lexical'/'outer' keyword idea; seems we're 
> just waiting for someone to write a PEP...

A "lexical" keyword would (sorry, I haven't googled for the 
discussions, so I'm guessing what was proposed: essentially the same as 
the "global" keyword) certainly be least surprising to Pythoneers, but 
it would require the introduction of a new keyword, which means any 
such proposal is likely to be rejected.

An alternative solution, coming from the "Classes are Python's 
mechanism for sharing state" school of thought, could be to endow 
classes and instances with the function descriptors which are 
responsible for binding methods - not sure what would happen when you 
want an instance method to be bindable again ... or some approach based 
on subclassing FunctionType.

But the bottom line is, when I want functions which happen to have some 
state, I really don't want to have to go to the hassle of simulating 
them with classes. Closures are an extremely, simple, easy, clear and 
efficient way of adding state to a functon. It's just a pity that that 
state is not mutable.


[*]  I may be wrong about this, as I don't actually use the class 
version myself, so I don't really care ... but I think there was an 
issue with MethodType not being instantiable before Python2.3 (or 
something along those lines, at least). IIRC, Michael Hudson pointed 
out to me that something which I assumed did not work (because it 
didn't in 2.2), actually did work (in 2.3) ... all on c.l.py.





More information about the Python-list mailing list