The other day while writing some code in Python, I had an idea. The bit of code I was writing was shaped something like this:
for a in results: if a.something: do_action(a)
It occurred to me that if I were to write this as a list comprehension, then the "if" would combine with the "for" on the same line:
[do_action(a) for a in results if a.something]
What if I could write this instead:
for a in results if a.something: do_action(a)
This looks like a nice compact syntax for a reasonably common construct, which happens to also be nicely aligned with the list comprehension syntax. I thought I'd have a go at modifying the Python language to accept this, and perhaps even submit a PEP (Python Enhancement Proposal) for the core language.
I read about the PEP process, found a related PEP to enhance the generator syntax (from 2009), which led me to a long thread discussing that PEP, from which I found a discussion about an "if-syntax for regular for-loops" (from 2008), and finally Guido's opinion on the matter (from 2006), which states that he doesn't like it and that it was proposed and rejected before. And as it turns out, after all that I agree with Guido.
Lessons learned (none the hard way!):
It seems to me that what you want grammatically is:
for a in results where a.something:
do_action(a)
since "if" doesn't really work for readability there (even if it does reduce the number of tokens that the tokenizer needs to know about).
I'm pretty sure I've used a language with a construct like that, but I can't remember for sure what it is -- possibly PICK BASIC, or one of its derivatives.
FWIW, the Perl equivalent would be:
foreach my $a in (grep { $_->something() } @results) {
do_action($a);
}
which loses a certain something in readability, but is none the less quite handy at times. (Typically when I use a construct like that I'll do the grep outside the foreach construct, with something like:
my @filtered_results = grep { $_->something() } @results;
I keep meaning to look at python more closely as an alternative to perl. But each time I consider it, I find python too "low level" for the type of programming I'm doing for reasons like this. (Which is ironic as the first serious programming I did was Z80 assembler.)
Ewen
I agree that "where" reads slightly better than "if", but Python already uses "if" for that purpose in the list generator context. Perhaps the language you're thinking of is SQL? :)
The Python equivalent of that Perl would be (using generator syntax):
for a in (x for x in a if x.something):
do_action(a)
which is reasonably convenient but awkwardly introduces a new identifier x (which is limited in scope to the generator expression itself). I felt that this would read better if I could use a.something instead of x.something which motivated the above idea. Perl actually has the same issue by using $_ instead of $a in the test.
Python is an excellent language without all the extra unreadability introduced by Perl. What sort of programming are you doing where Python would be too low level but Perl isn't?
map {}
and grep {}
, loop constructions that can test their exit condition, and regular expressions. (I fear this means that I'm a secret LISP programmer.) The python equivalent idiomatic constructs seem less convenient. But that could just be lack of time with the language. (I didn't remember the python generator syntax until you pointed it out, for instance.)
Perl: map {$_*$_} grep {$_ & 1} @a;
Python: [x*x for x in a if x & 1]
2009-10-20T09:43:22Z