PEP: 309 Title: Built-in Closure Type Version: $Revision$ Last-Modified: $Date$ Author: Peter Harris Status: Draft Type: Standards Track Content-Type: text/x-rst Created: 08-Feb-2003 Python-Version: 2.4 Post-History: Abstract ========= This proposal is for a built-in closure type for Python that allows a new callable to be constructed from another callable and a partial argument list (including positional and keyword arguments). A concise syntax shorthand for closures is suggested (tentatively). Motivation =========== Closures are useful as functional 'sections' or as convenient anonymous functions for use as callbacks. In some functional languages, (e.g. Miranda) you can use an expression such as ``(+1)`` to mean the equivalent of Python's ``(lambda x: x + 1)``. In general, languages like that are strongly typed, so the compiler always knows the number of arguments expected and can do the right thing when presented with a functor and less arguments than expected. Python has more flexible argument-passing, and so closures cannot be implicit in the same way. Instead of using them, a Python programmer will probably either define another named function or use a lambda. But lambda syntax is horrible, especially when you want to do something complex. We need something better. Rationale ========== Here is one way to do closures in Python:: class closure(object): def __init__(self, fn, *args, **kw): self.fn, self.args, self.kw = (fn, args, kw) def __call__(self, *args, **kw): d = self.kw.copy() d.update(kw) return self.fn(*(self.args + args), **d) Note that when the closure is called, positional arguments are appended to those provided to the constructor, and keyword arguments override and augment those provided to the constructor. So ``closure(operator.add,1)`` is a bit like ``(lambda x: 1+x)``, and ``closure(Tkinter.Label,fg='blue')`` is a callable like the Tkinter Label class, but with a blue foreground by default. I think a built-in type called ``closure``, that behaves the same way but maybe implemented more efficiently, would be very useful. Tentative Syntax Proposal ========================== I know syntax proposals have the odds stacked against them, and introducing new punctuation characters is frowned upon, but I think closures are a sufficiently powerful abstraction to deserve it. I propose the syntax ``fn@(*args,**kw)``, meaning the same as ``closure(fn,*args,**kw)``. I have no idea what havoc this would wreak on the parser. At least there are no backwards-compatibility issues because the @ character isn't a legal operator in any previous versions of Python. The @ sign is used in some assembly languages to imply register indirection, and the use here is also a kind of indirection. ``f@(x)`` is not ``f(x)`` , but a thing that becomes ``f(x)`` when you call it. Examples of Use --------------- Using closures as callbacks with bound arguments:: def handler(arg1, arg2, opt=0): #whatever... button1 = Button(window, text="Action A", command=handler@('A','1')) button2 = Button(window, text="Action B", command=handler@('B','2',opt=1)) Convenience functions :: nextarg = sys.argv.pop@(0) Copyright ========= This document has been placed in the public domain. .. Local Variables: mode: indented-text indent-tabs-mode: nil sentence-end-double-space: t fill-column: 70 End: