A friendlier, sugarier lambda -- a proposal for Ruby-like blocks in python
brenocon at gmail.com
brenocon at gmail.com
Sat Oct 14 06:54:09 CEST 2006
Hi all --
Compared to the Python I know and love, Ruby isn't quite the same.
However, it has at least one terrific feature: "blocks". Whereas in
"block" is just several lines of locally-scoped-together code, in Ruby
"block" defines a closure (anonymous function). To avoid confusion
them Ruby block-closures. I see them as just a syntax for defining
and passing them into method calls. I think something analogous could
to Python in a very simple manner that would make closures much more
and usable, and nail some use cases nicely.
To define a new closure and pass it into a function call, there are two
methods: inline 'def' and 'lambda'. Consider the following Twisted-ish
deferred = fetchPage('http://python.org')
print "fancy formatting: %s" % response.text
Lots of Twisted code has to be written backwards like this.
might be nice to use lambda right in the addCallback() call, like:
deferred.addCallback(lambda r: print("fancy formatting %s"
But this is awkward since the lambda is constrained to be one line; you
come back later and add much to the callback's code. Furthermore, this
isn't even legal, because 'print' isn't a function, but a statement --
is further constrained to only contain an expression.
Many have complained about this crippled-ness of lambda, but it
some sense. Since Python uses colons and indentation to define blocks
it would be awkward to close a multiline lambda. The best I could
would look like
print("fancy formatting %s" % r.text)
That trailing paranthesis is WAY un-Pythonic. We don't close code
that! And in general, declaring big multiline anonymous functions in
middle of a list of normal variable arguments is weird -- it just
It's perfectly legal to pass in 4 closures, interspersed with number
arguments. Imagine defining all of those inline with 'lambda'
And what about nesting? And then there's the term "lambda", while a
homage to Lisp and computation theory, just isn't the friendliest
(from my limited understanding,) Ruby block-closures assume a specific
case: You want to pass exactly one multiline, defined-right-there
closure to a
method when calling it. Therefore, you should get to define the
*immediately following* the method call. I suggest a Python version
keyword 'using' (or 'with'?) that takes the block of code as a closure,
passes it to the method call as the *last argument*. The above example
deferred.addCallback() using response:
print "fancy formatting %s" % response.text
and in general, the following two code snippets are equivalent:
[do stuff with x and y]
function_with_callback(a,b,c) using x,y:
[do stuff with x and y]
... where function_with_callback wants a 2-arg function as its last
It gets to call _f, or equivalently the defined-right-there
however it wants to -- wait for an I/O operation to finish, whatever.
so hot about the fact that it looks like addCallback() should be
before the 'using' keyword kicks in, but this is the simplest I could
This syntax does not let you define a new function and store it as a
variable. Python already has inline 'def' for that (that is, you can
'def' in any block of code you want, and it stays local to that scope.)
does not, strictly speaking, let you do anything new -- as Guido has
you could ditch lambda and achieve the equivalent by declaring the
callback function as an inline 'def', like in the first deferred
This only optimizes for the case of defining a closure only for the
passing it in as an argument to a method. However, this must be the
for anonymous functions in Python, since we already have inline 'def'.
always felt that passing in a lambda in lisp and python, or the
always awkward. You have to think about defining a new anonymous
*within* your method call and such, and then you have to close
after it -- it's just weird, I dunno.
This proposal could also handle some of the use cases mentioned in PEP
340. If you design your callback-taking functions to have only one
and have it as the last argument, you can trivially write lock
'using' for a no-arg block-closure):
def protect(lock, f):
[do stuff that needs myLock to be acquired]
Of course, the definition of protect() might have try/finally wrapped
the f() call. (Interestingly, this starts looking like a way to define
control-like structures. I haven't thought through the implications.)
ActiveRecord, Rails' object-relational mapper, does almost exactly this
database transactions, and I have found it quite nice:
# User is a sqlobject/sqlalchemy/django/whatever ORM class;
# User.transaction is a class method executing its passed-in
# the user table's START TRANSACTION and STOP TRANSACTION.
user1, user2 = getTwoUsers()
User.transaction() using user1, user2:
There might be some sort of overlap with PEP 343 and the 'with'
I'm not sure exactly. Sorry I'm late to the game and commenting on
PEP's, but I've only started reading them. Note that PEP's 343 and 340
very focused on resource management -- but I think that letting one
blocks as closures could make resource handling routines be easily
Python. Furthermore, tons more stuff -- like Deferreds and such --
added. (Ruby uses block-closures to do really basic constructs such as
iteration. Python does a fine job with "for x in L" and list and
comprehensions... enough so that map/lambda is obsolete! I'm just
see if there are use cases in Python for block-closures.)
I've been trying to search for similar proposals but have come up dry.
Anything like this out there? I hear Ruby blocks are heavily inspired
Smalltalk; anyone know more?
Is it feasible to assume the primary use of closures is as part of an
list, and such argument lists will want only one argument that is a
Does doing so avoid any big annoyances of functional programming?
Is this completely, totally incompatible with the current state of
previous deliberations :) ? e.g. I haven't thought much about how this
interact with yield and generators.
But really, I'm just idly curious -- does anyone think this might be
More information about the Python-list