diff --git a/pep-0309.txt b/pep-0309.txt new file mode 100644 index 000000000..fdd3b6205 --- /dev/null +++ b/pep-0309.txt @@ -0,0 +1,125 @@ +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: +