473,765 Members | 1,940 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

A friendlier, sugarier lambda -- a proposal for Ruby-like blocks in python

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
Python a
"block" is just several lines of locally-scoped-together code, in Ruby
a
"block" defines a closure (anonymous function). To avoid confusion
let's call
them Ruby block-closures. I see them as just a syntax for defining
closures
and passing them into method calls. I think something analogous could
be added
to Python in a very simple manner that would make closures much more
readable
and usable, and nail some use cases nicely.

To define a new closure and pass it into a function call, there are two
current
methods: inline 'def' and 'lambda'. Consider the following Twisted-ish
code:

deferred = fetchPage('http ://python.org')
def _showResponse(r esponse)
print "fancy formatting: %s" % response.text
deferred.addCal lback(_showResp onse)

Lots of Twisted code has to be written backwards like this.
Theoretically, it
might be nice to use lambda right in the addCallback() call, like:

deferred.addCal lback(lambda r: print("fancy formatting %s"
%r.text) )

But this is awkward since the lambda is constrained to be one line; you
can't
come back later and add much to the callback's code. Furthermore, this
example
isn't even legal, because 'print' isn't a function, but a statement --
lambda
is further constrained to only contain an expression.

Many have complained about this crippled-ness of lambda, but it
actually makes
some sense. Since Python uses colons and indentation to define blocks
of code,
it would be awkward to close a multiline lambda. The best I could
think of
would look like

deferred.addCal lback(lambda r:
print("fancy formatting %s" % r.text)
)

^
|

That trailing paranthesis is WAY un-Pythonic. We don't close code
blocks like
that! And in general, declaring big multiline anonymous functions in
the
middle of a list of normal variable arguments is weird -- it just
doesn't fit.
It's perfectly legal to pass in 4 closures, interspersed with number
and string
arguments. Imagine defining all of those inline with 'lambda'
expressions!
And what about nesting? And then there's the term "lambda", while a
great
homage to Lisp and computation theory, just isn't the friendliest
programming
vocab term.

(from my limited understanding,) Ruby block-closures assume a specific
use
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
closure
*immediately following* the method call. I suggest a Python version
with a
keyword 'using' (or 'with'?) that takes the block of code as a closure,
and
passes it to the method call as the *last argument*. The above example
becomes:

deferred.addCal lback() using response:
print "fancy formatting %s" % response.text

and in general, the following two code snippets are equivalent:
def _f(x,y):
[do stuff with x and y]
function_with_c allback(a,b,c, _f)

function_with_c allback(a,b,c) using x,y:
[do stuff with x and y]
next_statement( )

.... where function_with_c allback wants a 2-arg function as its last
argument.
It gets to call _f, or equivalently the defined-right-there
closure/ruby-block,
however it wants to -- wait for an I/O operation to finish, whatever.
I'm not
so hot about the fact that it looks like addCallback() should be
completed
before the 'using' keyword kicks in, but this is the simplest I could
think of.

This syntax does not let you define a new function and store it as a
local
variable. Python already has inline 'def' for that (that is, you can
do a
'def' in any block of code you want, and it stays local to that scope.)
It
does not, strictly speaking, let you do anything new -- as Guido has
stated,
you could ditch lambda and achieve the equivalent by declaring the
little
callback function as an inline 'def', like in the first deferred
example here.

This only optimizes for the case of defining a closure only for the
purpose of
passing it in as an argument to a method. However, this must be the
only use
for anonymous functions in Python, since we already have inline 'def'.
I've
always felt that passing in a lambda in lisp and python, or the
equivalent
anonymous function(x,y) {} in javascript, or anonymous classes in java,
was
always awkward. You have to think about defining a new anonymous
function
*within* your method call and such, and then you have to close
parantheses
after it -- it's just weird, I dunno.

This proposal could also handle some of the use cases mentioned in PEP
310 and
340. If you design your callback-taking functions to have only one
callback
and have it as the last argument, you can trivially write lock
acquition (omit
'using' for a no-arg block-closure):

def protect(lock, f):
lock.acquire()
f()
lock.release()

protect(myLock) :
[do stuff that needs myLock to be acquired]

Of course, the definition of protect() might have try/finally wrapped
around
the f() call. (Interestingly, this starts looking like a way to define
new
control-like structures. I haven't thought through the implications.)

ActiveRecord, Rails' object-relational mapper, does almost exactly this
for
database transactions, and I have found it quite nice:

# User is a sqlobject/sqlalchemy/django/whatever ORM class;
# User.transactio n is a class method executing its passed-in
closure within
# the user table's START TRANSACTION and STOP TRANSACTION.

user1, user2 = getTwoUsers()
User.transactio n() using user1, user2:
someRaceConditi onProneStuff(us er1, user2)
moreRaceConditi onProneStuff(us er1, user2)

There might be some sort of overlap with PEP 343 and the 'with'
statement, but
I'm not sure exactly. Sorry I'm late to the game and commenting on
last year's
PEP's, but I've only started reading them. Note that PEP's 343 and 340
are
very focused on resource management -- but I think that letting one
define code
blocks as closures could make resource handling routines be easily
written in
Python. Furthermore, tons more stuff -- like Deferreds and such --
could be
added. (Ruby uses block-closures to do really basic constructs such as
foreach
iteration. Python does a fine job with "for x in L" and list and
generator
comprehensions. .. enough so that map/lambda is obsolete! I'm just
trying to
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
by
Smalltalk; anyone know more?

Is it feasible to assume the primary use of closures is as part of an
argument
list, and such argument lists will want only one argument that is a
closure?
Does doing so avoid any big annoyances of functional programming?

Is this completely, totally incompatible with the current state of
Python and
previous deliberations :) ? e.g. I haven't thought much about how this
would
interact with yield and generators.

But really, I'm just idly curious -- does anyone think this might be
useful?
Take care,
Brendan

Oct 14 '06
26 2727
Kay Schluehr wrote:
The with statement is already implemented in Python 2.5.

http://docs.python.org/whatsnew/pep-343.html

The main difference between the with statement and Ruby blocks is that
the with-statement does not support loops. Yielding a value of a
function decorated with a contextmanager and passing it to the BLOCK of
the with statement is essentially a one-shot. Therefore you can't use
the with statement to define iterators. It is not a lightweight visitor
pattern replacement as it is in Ruby. Hence the with- and the
for-statement are orthogonal to each other in Python.
Thanks or the What's-New link, it clarified things for me. So there
are several ways to do things with code blocks now in python..
* for/while define loops around their blocks
* if defines contional control into its block
* with defines startup/cleanup context surrounding its block

Twisted addCallback() is a different pattern than either of these. The
code is deferred to execute at some later time. If there are many more
patterns of things you could want to do with a block, it might be nice
to have a blocks-are-closures mechanism.

Oct 14 '06 #11
br******@gmail. com wrote:
Compared to the Python I know and love, Ruby isn't quite the same.
However, it has at least one terrific feature: "blocks".
Well, I particularly like how Boo (http://boo.codehaus.org) has done
it:

func(a, b, c) def(p1, p2, p3):
stmts

I was so attached to these "nameless" def-forms that I was even shocked
when I found that this doesn't work in python:

f = def(a, b):
return a*b

Another good feature of Boo, btw.

Oct 14 '06 #12
Alexey Borzenkov:
I was so attached to these "nameless" def-forms that I was even shocked
when I found that this doesn't work in python:
f = def(a, b):
return a*b
Another good feature of Boo, btw.
I think Boo has some good things worth consideration (and maybe worth
to copy) and some bad things that I like less than Python ones.
Turning def and class into functions reduces the need of lambdas
(compared to a lambda the required return is the only thing in the way)
and I like it, but maybe it reduces code readabilty a bit for people
that have just started to program:

mul2 = def(a, b):
return a * b

Instead of:

def mul2(a, b):
return a * b

The lightweight Io language uses an even simpler approach, some
examples:
http://www.iolanguage.com/about/samplecode/
An example:

factorial := method(n, if(n == 1, 1, n * factorial(n - 1)))

The "method" function is used to define functions...

Bye,
bearophile

Oct 14 '06 #13
be************@ lycos.com wrote:
but maybe it reduces code readabilty a bit for people
that have just started to program:

mul2 = def(a, b):
return a * b

Instead of:

def mul2(a, b):
return a * b
For such simple cases, yes. What about:

button.click += def(obj):
# do stuff

You obviously can't:

def button.click(ob j):
# do stuff

:-) And if you make intermediate function and then assign it somewhere,
it "pollutes namespace": it's still left there, unneeded.

Oct 15 '06 #14
Paul Boddie wrote:
Kay Schluehr wrote:

Spreading tiny function definitions all over the code
may be finally not such a good idea compared with a few generic methods
that get just called? OO might run out of fashion these days but Python
is not Java and Pythons OO is pretty lightweight.

I think you've successfully identified a recent trend in Python
development: the abandonment of fairly transparent object-oriented
techniques in favour of more opaque but supposedly more convenient
hybrid techniques. Unlike Java, Python's first class functions and
methods are already highly useful for callback-based systems - such
systems in Java suffer from interface proliferation and needless
one-off class definitions - but it seems to me that the subsequent
language evolution in favour of anonymous blocks brings fewer benefits
and can, as you say, diminish readability.
I was actually more concerned about extensibility than readability.
Talking about classes being lightweight I mentioned classes to be
"first-class" objects and intended constructions like this:

class fetchPage_event (fetchPage('htt p://python.org')):
def _showResponse(s elf, response)
print "fancy formatting: %s" % response.text

where all the registration and framework magics happens when the
fetchPage_event class is created. Adding "callbacks" just happen when
you add a method to the class. Here you have your "block" with no
additional syntax. You can pass the fetchPage_event class around and
add and overwrite methods in subclasses in the same fashion. A subclass
can be created within any statement on the fly etc. Here you have an OO
solution that is both short and has a clean design.

Oct 15 '06 #15
*************** ********
Your mail has been scanned by InterScan MSS.
*************** ********
Hello,

Sorry, I very new in programming and the use of the classes still unknown.
I'm really interested to apply the right one as far as the results aren't as
expected.

Here's the example:

from poplib import POP3
ProtocolError = 'Error in Protocol' # handler for IMAP4 and POP3 errors

try:
_pop = POP3(args[0])
_pop.user(args[1])
except:
raise ProtocolError
a.append( 'STAT = POP Server %s reply\n %s\n' %(args[0], _pop.pass_(args[2])))
(numMsgs, totalSize) = _pop.stat()
for cnt in range(1, numMsgs +1):
#Need a cleanup for the envelope header 'Unix-From'

try:
msgs =_pop.top(cnt,0 )[1]
except:
raise ProtocolError

# Here I'd like to have some part removed and I known that some class in email
# will do the neat job without missing any of the needed detail

hdrs = [k for itms in ('from', 'to', 'cc',
'date', 'subject', 'reply-to', 'message-')
for k in msgs if k.startswith(it ms.capitalize() )]

# This isn't the right risult. Some time missing one of the wanted item.

_pop.quit()

I've put my opinions as comments, in order to copy and try. The args contains
(pop address, user, and password) respectively.
The list comprehension fails for some comparison, might be more accurate a
regex, I just fill too complicated for a simple scan and I know that there
are already good classes that will do the right way. I just miss the learning
how to use them.

This a part of a small program, which will attempt to organize all the emails,
locals and remote in order to do spam removal and/or backup the good ones.
I'd like somebody to join, not for a speedy result but for a joy of exchanging
technics and tricks.

F

Oct 15 '06 #16
br******@gmail. com wrote:
Kay Schluehr wrote:
The with statement is already implemented in Python 2.5.

http://docs.python.org/whatsnew/pep-343.html

The main difference between the with statement and Ruby blocks is that
the with-statement does not support loops. Yielding a value of a
function decorated with a contextmanager and passing it to the BLOCK of
the with statement is essentially a one-shot. Therefore you can't use
the with statement to define iterators. It is not a lightweight visitor
pattern replacement as it is in Ruby. Hence the with- and the
for-statement are orthogonal to each other in Python.

Thanks or the What's-New link, it clarified things for me. So there
are several ways to do things with code blocks now in python..
* for/while define loops around their blocks
* if defines contional control into its block
* with defines startup/cleanup context surrounding its block

Twisted addCallback() is a different pattern than either of these. The
code is deferred to execute at some later time. If there are many more
patterns of things you could want to do with a block, it might be nice
to have a blocks-are-closures mechanism.
That's true. As I mentioned in my response to Paul Boddie I do think it
is a poor solution even in Ruby(!) but I agree that given the situation
we just have with poorly designed application frameworks ( no illusion:
they won't ever go away and I do not pretend to be smarter and doing it
better in any case ) blocks are a quite nice feature for providing ad
hoc solutions. I consider them as somewhat aligned with a
worse-is-better philosophy.

----

I recently created an extended lambda as an example for my EasyExtend
language extension framework for Python. These kind of showcases are,
at least for me, important for getting programming practice within the
system and explore and extend the framework. The two things I cared
about when altering the semantics of lambda were:
1) Enabling multiple expressions separated by ';'
2) Enabling so called "simple statements"

Python does not only distinguish between expressions and statements but
also between simple and compound statements within its grammar
description. A compound statement is typically multiline and contains a
block. A simple statement is something like print, exec, raise or
assert containing no block. So I actually extended lambda to the limit
of an anonymous closure containing no block.

One might take this into consideration and alter the premises. But this
would be up to you, breno. At the moment I do not recommend using EE
because it is under heavy reconstruction but for the not so distant
future ( end of november is my personal deadline for the next release )
I recommend taking a look on it by anyone who aims to walk the RoR path
of a customized domain specific language for Python. For those who are
dilligent there are will be quite a lot of examples. For some it might
be even fun.

Oct 15 '06 #17
Alexey Borzenkov wrote:
be************@ lycos.com wrote:
but maybe it reduces code readabilty a bit for people
that have just started to program:

mul2 = def(a, b):
return a * b

Instead of:

def mul2(a, b):
return a * b

For such simple cases, yes. What about:

button.click += def(obj):
# do stuff

You obviously can't:

def button.click(ob j):
# do stuff

:-) And if you make intermediate function and then assign it somewhere,
it "pollutes namespace": it's still left there, unneeded.
If you're really uptight about it you can
def temp_function(. ..):
....
button.click = temp_function
del(temp_functi on)

But for something like the example I'd probably just use a local name
wherever the definition is needed; there's no namespace pollution in
any meaningful sense then.

Oct 15 '06 #18
On Sat, 14 Oct 2006 09:00:53 +0000, James Stroud wrote:
Compared to the Python I know and love, Ruby isn't quite the same.
However, it has at least one terrific feature: "blocks".
[snip 220-odd quoted lines]
http://mail.python.org/pipermail/pyt...il/215805.html

Hi James,

You seem to have mislaid your snipper. It is very useful for when you're
replying to a very large post, and all you want to do is add a single line
at the end. It reduces frustration in readers who find themselves
scrolling, and scrolling, and scrolling, and scrolling through quoted text
they've already read, wondering why you've quoted all this stuff if you
aren't actually commenting on it, and prevents readers from unfairly
dismissing you as just another "metoobie".

--
Steven.

Oct 15 '06 #19
Paul Boddie wrote:
Kay Schluehr wrote:
>Spreading tiny function definitions all over the code
may be finally not such a good idea compared with a few generic methods
that get just called? OO might run out of fashion these days but Python
is not Java and Pythons OO is pretty lightweight.

I think you've successfully identified a recent trend in Python
development: the abandonment of fairly transparent object-oriented
techniques in favour of more opaque but supposedly more convenient
hybrid techniques.
Just for the record : Ruby's code-blocks (closures, really) come from
Smalltalk, which is still the OneTrueObjectLa nguage(tm).
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom. gro'.split('@')])"
Oct 16 '06 #20

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
351
by: e | last post by:
here's what is probably an unusual question:
10
2287
by: Neal | last post by:
I'm beginning some experiments with Ruby in XHTML 1.1. I'm finding very odd results which surprise me. I'm using a PHP snippet which serves application/xml+xhtml and XHTML 1.1 to those browsers which accept it, and text/html XHTML 1.0 otherwise. I included a simple Ruby setup, first without using the <rp> elements, then with. My results? O7.23 does not render simple Ruby with the overtext as described in the spec, but does not display...
30
2173
by: Mike Meyer | last post by:
I know, lambda bashing (and defending) in the group is one of the most popular ways to avoid writing code. However, while staring at some Oz code, I noticed a feature that would seem to make both groups happy - if we can figure out how to avoid the ugly syntax. This proposal does away with the well-known/obscure "lambda" keyword. It gives those who want a more functional lambda what they want. It doesn't add any new keywords. It doesn't...
5
2522
by: Max Rybinsky | last post by:
Hello! Please take a look at the example. >>> a = # Just a list of tuples >>> a Now i want to get a list of functions x*y/n, for each (x, y) in a:
4
2631
by: Xah Lee | last post by:
A Lambda Logo Tour (and why LISP languages using λ as logo should not be looked upon kindly) Xah Lee, 2002-02 Dear lispers, The lambda character λ, always struck a awe in me, as with other mathematical symbols. In my mind, i imagine that those obscure math
23
5332
by: Kaz Kylheku | last post by:
I've been reading the recent cross-posted flamewar, and read Guido's article where he posits that embedding multi-line lambdas in expressions is an unsolvable puzzle. So for the last 15 minutes I applied myself to this problem and come up with this off-the-wall proposal for you people. Perhaps this idea has been proposed before, I don't know. The solutions I have seen all assume that the lambda must be completely inlined within the...
9
21084
Niheel
by: Niheel | last post by:
I've used the following tutorials to help be get a better understanding of Ruby On Rails or ROR. Installing Ruby on Rails - Fedora / Lighthttpd Tutorial & Setup for Ruby on Rails Rolling with Ruby on Rails Rolling with Ruby on Rails - Part II Learn to Program with Ruby - by Chris Pine Programming Ruby - Pragmatic Programmer's Guide Ruby User's Guide - Mark Slagell
10
3795
by: lawrence k | last post by:
I work mostly in PHP, but at the web design firm where I work we are thinking of switching to Ruby on Rails. Our lead designer recently installed Typo on a client's site and he said to us, with surprise, "All Ruby On Rails software has the same directory layout?" That was a revelation to him. He was used to the PHP scene, where diversity is the rule. I've done some google searches and I see that the subject has seen a fair amount of...
1
2629
by: Tim H | last post by:
Compiling with g++ 4: This line: if_then_else_return(_1 == 0, 64, _1) When called with a bignum class as an argument yields: /usr/include/boost/lambda/if.hpp: In member function 'RET boost::lambda::lambda_ functor_base<boost::lambda::other_action<boost::lambda::ifthenelsereturn_action>
0
9393
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10153
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10007
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
9946
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9832
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8830
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7371
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5272
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5413
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.