Built-in Closure Type, by Peter Harris
This commit is contained in:
parent
67273248cc
commit
d49ecf85a2
|
@ -0,0 +1,125 @@
|
||||||
|
PEP: 309
|
||||||
|
Title: Built-in Closure Type
|
||||||
|
Version: $Revision$
|
||||||
|
Last-Modified: $Date$
|
||||||
|
Author: Peter Harris <scav@blueyonder.co.uk>
|
||||||
|
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:
|
||||||
|
|
Loading…
Reference in New Issue