In list/generator comprehension, currently we have no way to access the result of the expression and have to write something like this:
[f(x) for x in l if f(x) > 0]
if f() is heavy or nonpure (i.e. have side effects), calling f() twice might be undesirable.
Even if f() is not a function such as
[x + 1 for x in l if x + 1 > 0]
it looks ugly since we're repeating ourself.
We can work around it like this:
[y for y in (f(x) for x in l) if y > 0]
but then we have an unnecessary nested loop comprehension.
I'm suggesting about something like:
[f(x) for x in l if @ > 0]
where @ is the result of the listcomp's expression (i.e. f(x))
Personally, I don't like the use of symbols like @, as python is not perl. I'm still thinking of a better syntax/approach and is open for suggestion.
What do you guys think?
On Fri, Jun 19, 2009, Lie Ryan wrote: >
In list/generator comprehension, currently we have no way to access the result of the expression and have to write something like this:
[f(x) for x in l if f(x) > 0]
if f() is heavy or nonpure (i.e. have side effects), calling f() twice might be undesirable.
Listcomps and genexps are like lambdas: run up against their limits and
Aahz (aahz@pythoncraft.com) <*> http://www.pythoncraft.com/
"as long as we like the same operating system, things are cool." piranha
Aahz wrote:
On Fri, Jun 19, 2009, Lie Ryan wrote:
In list/generator comprehension, currently we have no way to access the result of the expression and have to write something like this:
[f(x) for x in l if f(x) > 0]
if f() is heavy or nonpure (i.e. have side effects), calling f() twice might be undesirable.
Listcomps and genexps are like lambdas: run up against their limits and you should switch to a regular for loop or generator.
I think of it not as limitation but as an odd gap in functionality. I think having the semantics that the filtering is done after the expression part would be much more useful than the current behavior (filtering before expression).
If filtering is done after expression, we can access both the original and the transformed objects (it may also be possible to optimize the cases where the filter does not use the transformed objects, although this complex behavior wouldn't be pythonic)
Try rewriting this:
res = [x**x as F for x in nums if F < 100] (note: this is my new preferred syntax)
Attempts:
res = [] for x in nums: F = x**x if F < 100: res.append(F)
remarks: five lines that's much more difficult to understand than a single, concise expression in standard form.
res = [F for F in (x**x for x in nums) if F < 100]
remarks: using nested list comprehension is DRY (on a loose definition of DRY principle). I have to repeat the comprehension body twice, when I only need one expression and one filtering.
res = [F for F in map(lambda x: x**x, nums) if F < 100]
remarks: when the expression part is just a simple expression, you have to use lambda and that's plain ugly. Not to mention when you want to filter based on both x and F.
Advantages of the proposal:
as
keyword, no new keyword and no ambiguity since currently
as
cannot exist inside comprehension.Disadvantages:
as
keyword.
(As "simple is better than complex", I actually don't really like as
can change evaluation order; I much prefer to keep everything simple and
consistent, i.e. always evaluate expression then filter or otherwise)possible syntaxes:
On Fri, Jun 19, 2009 at 12:39 AM, Lie Ryanlie.1296@gmail.com wrote:
Aahz wrote:
On Fri, Jun 19, 2009, Lie Ryan wrote:
In list/generator comprehension, currently we have no way to access the result of the expression and have to write something like this:
[f(x) for x in l if f(x) > 0]
if f() is heavy or nonpure (i.e. have side effects), calling f() twice might be undesirable.
Listcomps and genexps are like lambdas: run up against their limits and you should switch to a regular for loop or generator.
I think of it not as limitation but as an odd gap in functionality. I think having the semantics that the filtering is done after the expression part would be much more useful than the current behavior (filtering before expression).
If filtering is done after expression, we can access both the original and the transformed objects (it may also be possible to optimize the cases where the filter does not use the transformed objects, although this complex behavior wouldn't be pythonic)
Try rewriting this:
res = [x**x as F for x in nums if F < 100] (note: this is my new preferred syntax)
Attempts:
res = [] for x in nums: F = x**x if F < 100: res.append(F)
remarks: five lines that's much more difficult to understand than a single, concise expression in standard form.
Depends on how complicated the "standard form" is; right now, it (list comps) is/are relatively simple. Perl syntax is concise and adheres to a standard, but is not easy to understand. Not to equate a minor syntax addition to Perl, but every addition is a step in that general direction. The road to hell was paved with good intentions.
Cheers,
2009/6/19 Lie Ryan lie.1296@gmail.com:
res = [x**x as F for x in nums if F < 100] (note: this is my new preferred syntax) [...] Advantages of the proposal:
as
keyword, no new keyword and no ambiguity since currently
as
cannot exist inside comprehension.Disadvantages:
as
keyword.
(As "simple is better than complex", I actually don't really like as
can change evaluation order; I much prefer to keep everything simple and
consistent, i.e. always evaluate expression then filter or otherwise)possible syntaxes:
OK, with this explanation (and the new syntax) I see what you're getting at better.
However, changing the order of evaluate vs filter is a huge compatibility problem. There's no way this will be possible. Even with syntax triggering the change (so that it's one way with the "as", the other without), that's a disaster waiting to happen.
You have at least 3 explicit ways of stating your intent (genexp inside listcomp, map inside listcomp, explicit loop). None is as cleanlooking as your (amended) proposal, but they work now, and they don't have the semantic issues of your proposal.
(For a more general, more radical, equally certain to be shot down, option, which at least doesn't introduce the change in semantics, you could try proposing "as" as an assignmentasexpression operator. So you could have
[y for x in l if (f(x) as y) < 100]
Hmm, on second thoughts  no, don't bother... :))
Paul.
Paul Moore wrote:
2009/6/19 Lie Ryan lie.1296@gmail.com:
res = [x**x as F for x in nums if F < 100] (note: this is my new preferred syntax) [...] Advantages of the proposal:
as
keyword, no new keyword and no ambiguity since currently
as
cannot exist inside comprehension.Disadvantages:
as
keyword.
(As "simple is better than complex", I actually don't really like as
can change evaluation order; I much prefer to keep everything simple and
consistent, i.e. always evaluate expression then filter or otherwise)possible syntaxes:
OK, with this explanation (and the new syntax) I see what you're getting at better.
However, changing the order of evaluate vs filter is a huge compatibility problem. There's no way this will be possible. Even with syntax triggering the change (so that it's one way with the "as", the other without), that's a disaster waiting to happen.
How about this syntax which would solve your concern for the semantic change:
[x**x as F for x in lst if F() < 100]
it's similar to original as
proposal, except that F is a callable
instead of direct value.
The advantage of F being callable is that it does not need semantic change, the filtering part will be done before expression just like it is right now. However, we can explicitly request for the expression to be evaluated by calling F(); the return value of F() will be saved and reused for the final result and other calls to F().
A diagrammatic explanation:
+
 this is the part that name
 the expression's callable

+
[x**x as F for x in lst if x and F() < 100 and isvalid(F())] + +   + +  the filtering part is     evaluated before     expression just like     current behavior     +       then when F gets called;    expression is evaluated,    cached, and returned    +     F is called again, return cached result   +   at the end of the day, if F is called,  return the cached result, else evaluate  the expression and use that +
using the ascallable syntax, the semantic of this:
[f(x) as F for x in lst if g(F())]
would be similar to:
result = [] for x in lst:
# F() ensures f(x) will be only ever be called once
def F():
nonlocal _cache
if not _cache:
_cache = f(x)
return _cache
_cache = None
if g(F()):
result.append(F())
the only disadvantage of this ascallable is if you forgot to call F.
You have at least 3 explicit ways of stating your intent (genexp inside listcomp, map inside listcomp, explicit loop). None is as cleanlooking as your (amended) proposal, but they work now, and they don't have the semantic issues of your proposal.
(For a more general, more radical, equally certain to be shot down, option, which at least doesn't introduce the change in semantics, you could try proposing "as" as an assignmentasexpression operator. So you could have
[y for x in l if (f(x) as y) < 100]
Hmm, on second thoughts  no, don't bother... :))
It took me several minutes to understand that one... and no, that syntax as makes it way too easy to be too creative in list comprehension, devaluing the "standard form" which IMO is the strongest point of list comprehension. Not to mention that that syntax moved the expression part to be inside the filtering part... which is quite... disturbing...
On Sat, 20 Jun 2009 09:45:58 am Lie Ryan wrote:
How about this syntax which would solve your concern for the semantic change:
[x**x as F for x in lst if F() < 100]
Let's look at what that would be equivalent to.
L = [] for x in lst: F = lambda x=x: x**x # Need to use default value in the
# lambda otherwise all elements will have the same value.
tmp = F()
if tmp < 100:
L.append(tmp)
It's not clear why you think this is an improvement over:
[x**x as F for x in lst if F < 100] # note the missing ()s
which would be equivalent to:
L = [] for x in lst: F = x**x if F < 100: L.append(F)
Despite what you say here:
The advantage of F being callable is that it does not need semantic change, the filtering part will be done before expression just like it is right now.
That's not true. It can't be true. If you want to filter on xx being greater than 100, you need to calculate xx first. In theory, a sufficiently clever compiler could recognise that, say, x**x < 100 implies 0 <= x < 3.59728 (approx), but in general, you can't predict the value of f(x) without actually calculating f(x).
What happens if you accidentally forget to put brackets after the F expression? Do you get a syntax error? Undefined behaviour? A runtime exception?
 Steven D'Aprano
Steven D'Aprano wrote:
The advantage of F being callable is that it does not need semantic change, the filtering part will be done before expression just like it is right now.
That's not true. It can't be true. If you want to filter on xx being greater than 100, you need to calculate xx first. In theory, a sufficiently clever compiler could recognise that, say, x**x < 100 implies 0 <= x < 3.59728 (approx), but in general, you can't predict the value of f(x) without actually calculating f(x).
Did you read the middle part of the post and the diagram, which address the question you're asking and how it would be handled?
What happens if you accidentally forget to put brackets after the F expression? Do you get a syntax error? Undefined behaviour? A runtime exception?
As F is just callable, F > 100 should result in comparison of number against callable. But as it is rare that you really actually wanted to do such thing, I think python can also be a little protective and issue a warning.
On Sun, 21 Jun 2009 04:08:05 am Lie Ryan wrote:
Steven D'Aprano wrote:
The advantage of F being callable is that it does not need semantic change, the filtering part will be done before expression just like it is right now.
That's not true. It can't be true. If you want to filter on xx being greater than 100, you need to calculate xx first. In theory, a sufficiently clever compiler could recognise that, say, x**x < 100 implies 0 <= x < 3.59728 (approx), but in general, you can't predict the value of f(x) without actually calculating f(x).
Did you read the middle part of the post and the diagram, which address the question you're asking and how it would be handled?
Yes. It made no sense to me at all.
Let's make a practical example:
c = 1246158315.0 # approximately a week from now L = filter(lambda t: t > c, [time.time() for x in range(20)])
becomes:
L = [time.time() as F for x in range(20) if F() > c]
How do you expect your proposed syntax to determine whether or not the current time is greater than c without actually checking the current time?
Note also that your proposal requires list comps to become like lambda. Using your earlier example:
[x**x as F for x in lst if F() < 100]
This doesn't bind the value of xx to the name F, but the expression xx to F. That makes it like a lambda:
lambda x: x**x
except the name x is implied and some sort of magic takes place to ensure that by the time you call F(), the appropriate value of x is still around. If this is to apply to generator expressions as well, calling F() could occur some arbitrarily large time later.
That means that
[time.time() for x in lst]
will create a list that looks something like:
[1245555766.5681751, 1245555767.2609128, ...]
but your proposed:
[time.time() as F for x in lst]
will create a list something like:
[<function F at 0x88a879c>, <function F at 0x88a8d84>, ...]
 Steven D'Aprano
Steven D'Aprano wrote:
On Sun, 21 Jun 2009 04:08:05 am Lie Ryan wrote:
Steven D'Aprano wrote:
The advantage of F being callable is that it does not need semantic change, the filtering part will be done before expression just like it is right now. That's not true. It can't be true. If you want to filter on xx being greater than 100, you need to calculate xx first. In theory, a sufficiently clever compiler could recognise that, say, x**x < 100 implies 0 <= x < 3.59728 (approx), but in general, you can't predict the value of f(x) without actually calculating f(x). Did you read the middle part of the post and the diagram, which address the question you're asking and how it would be handled?
Yes. It made no sense to me at all.
Let's make a practical example:
c = 1246158315.0 # approximately a week from now L = filter(lambda t: t > c, [time.time() for x in range(20)])
becomes:
L = [time.time() as F for x in range(20) if F() > c]
How do you expect your proposed syntax to determine whether or not the current time is greater than c without actually checking the current time?
Of course it will call F(). F() will evaluate time.time() and cache it so future call to F() do not need to call time.time() twice (resulting in different time used for filter and expression).
Note also that your proposal requires list comps to become like lambda. Using your earlier example:
[x**x as F for x in lst if F() < 100]
This doesn't bind the value of xx to the name F, but the expression xx to F. That makes it like a lambda:
lambda x: x**x
except the name x is implied and some sort of magic takes place to ensure that by the time you call F(), the appropriate value of x is still around. If this is to apply to generator expressions as well, calling F() could occur some arbitrarily large time later.
F() could be called when the filtering takes place or not be called at all, when it does gets called, the expression would be evaluated. In effect this moves forward the expression evaluation to the middle of filtering process.
That means that
[time.time() for x in lst]
will create a list that looks something like:
[1245555766.5681751, 1245555767.2609128, ...]
but your proposed:
[time.time() as F for x in lst]
will create a list something like:
[<function F at 0x88a879c>, <function F at 0x88a8d84>, ...]
Where did you get that idea? The comprehension would call F before appending it to the list. The equivalent forloop syntax also clearly stated that:
result = [] for x in lst:
# F() ensures f(x) will be only ever be called once
def F():
nonlocal _cache
if not _cache:
_cache = f(x)
return _cache
_cache = None
if g(F()):
# here F is called before it's appended,
# result is the same as calling f(x)
# but prevents evaluating f(x) twice
result.append(F())
On Fri, Jun 19, 2009 at 3:39 AM, Lie Ryanlie.1296@gmail.com wrote:
res = [x**x as F for x in nums if F < 100]
This, I have wanted.
That doesn't resolve all the issues others raised, but (at least for me), you just moved it from "a little worse than the status quo" to "hmm... that would be nice if it could be done without too many side effect on the rest of the language."
On the possibility that a more general problem sometimes spurs a more elegant solution, I'll point out that I have more often wanted access to the previous or following element, and that my desired filters on the results are often reliant on the resultssofar.
Disadvantages:
For What Its Worth, I'm not sure how strong that argument should be. Is this just a bizarre corner case, or is there lots of code that relies on it?
That ordering actually surprises me, because I expect python to evaluate left to right.
On the other hand, now that we have conditional expressions, consistency with those is probably more important, so maybe the number of people surprised by the current situation will go down with time.
jJ
Jim Jewett jimjjewett@gmail.com writes:
On Fri, Jun 19, 2009 at 3:39 AM, Lie Ryanlie.1296@gmail.com wrote:
res = [x**x as F for x in nums if F < 100]
This, I have wanted.
You have it:
res = [f for f in (x**x for x in nums) if f < 100]
In addition to the fact that this works now in existing Python, I find it clearer than the above syntax you say you want.
 \ “It's my belief we developed language because of our deep inner  `\ need to complain.” —Jane Wagner, via Lily Tomlin  _o__)  Ben Finney
Ben Finney wrote:
Jim Jewett jimjjewett@gmail.com writes:
On Fri, Jun 19, 2009 at 3:39 AM, Lie Ryanlie.1296@gmail.com wrote:
res = [x**x as F for x in nums if F < 100] This, I have wanted.
You have it:
res = [f for f in (x**x for x in nums) if f < 100]
In addition to the fact that this works now in existing Python, I find it clearer than the above syntax you say you want.
How about:
res = [F for x in nums with x**x as F if F < 100]
:)
On Sat, Jun 20, 2009 at 9:22 AM, MRABpython@mrabarnett.plus.com wrote:
Ben Finney wrote: >
Jim Jewett jimjjewett@gmail.com writes:
On Fri, Jun 19, 2009 at 3:39 AM, Lie Ryanlie.1296@gmail.com wrote:
res = [x**x as F for x in nums if F < 100]
This, I have wanted.
You have it:
res = [f for f in (x**x for x in nums) if f < 100]
In addition to the fact that this works now in existing Python, I find it clearer than the above syntax you say you want.
How about:
res = [F for x in nums with x**x as F if F < 100]
:)
That toggles the first part of the comprehensions to be or not be an expression, depending on if there is a with clause later. You could miss this when you read it, and it opens the door to doing more strange things, like:
res = [F/2 for x in nums with x**x as F if F < 100]
This is basically a strangely syntaxed nested loop
 Read my blog! I depend on your acceptance of my opinion! I am interesting! http://techblog.ironfroggy.com/ Follow me if you're into that sort of thing: http://www.twitter.com/ironfroggy
Calvin Spealman wrote:
On Sat, Jun 20, 2009 at 9:22 AM, MRABpython@mrabarnett.plus.com wrote:
Ben Finney wrote:
Jim Jewett jimjjewett@gmail.com writes:
On Fri, Jun 19, 2009 at 3:39 AM, Lie Ryanlie.1296@gmail.com wrote:
res = [x**x as F for x in nums if F < 100] This, I have wanted. You have it:
res = [f for f in (x**x for x in nums) if f < 100]
In addition to the fact that this works now in existing Python, I find it clearer than the above syntax you say you want.
How about:
res = [F for x in nums with x**x as F if F < 100]
:)
That toggles the first part of the comprehensions to be or not be an expression, depending on if there is a with clause later. You could miss this when you read it, and it opens the door to doing more strange things, like:
res = [F/2 for x in nums with x**x as F if F < 100]
This is basically a strangely syntaxed nested loop
I don't know what you mean.
def F(m, x): print m, x return x
[foo("value", x) for x in range(5) if foo("test", x) % 2] test 0 test 1 value 1 test 2 test 3 value 3 test 4 [1, 3]
The test is done first, so it's equivalent to:
results = [] for x in range(5): if foo("test", x) % 2: results.append(foo("value", x))
test 0 test 1 value 1 test 2 test 3 value 3 test 4
That means that:
res = [x**x for x in nums if x**x < 100]
is equivalent to:
res = []
for x in nums :
if x**x < 100:
res.append(x**x)
My suggestions turns:
res = []
for x in nums :
F = x**x # <== temporary variable
if F < 100:
res.append(F)
into:
res = [F for x in nums with x**x as F if F < 100]
^^^^^^^^^^^^^^
temporary variable
On Fri, Jun 19, 2009 at 2:39 AM, Lie Ryanlie.1296@gmail.com wrote:
res = [x**x as F for x in nums if F < 100]
In some languages, you can use "let" in a list comprehension:
[f  x < nums, let f = x**x, f < 100]
which I guess might look something like this in python:
[f for x in nums let f = x**x if f < 100]
(JavaScript actually has a let
keyword so I suspect we will
eventually adopt something like that.)
j
On Fri, 19 Jun 2009 05:39:32 pm Lie Ryan wrote:
Aahz wrote:
On Fri, Jun 19, 2009, Lie Ryan wrote:
In list/generator comprehension, currently we have no way to access the result of the expression and have to write something like this:
[f(x) for x in l if f(x) > 0]
if f() is heavy or nonpure (i.e. have side effects), calling f() twice might be undesirable.
Listcomps and genexps are like lambdas: run up against their limits and you should switch to a regular for loop or generator.
I think of it not as limitation but as an odd gap in functionality. I think having the semantics that the filtering is done after the expression part would be much more useful than the current behavior (filtering before expression).
The point of the filtering is to avoid needlessly calculating a potentially expensive expression only to throw it away.
If you want expression first, then filter, you can get that already in a oneliner:
filter(lambda x: x > 0, [f(x) for x in seq])
Don't create new syntax when there are perfectly good functions that do the job already.
 Steven D'Aprano
Steven D'Aprano wrote:
On Fri, 19 Jun 2009 05:39:32 pm Lie Ryan wrote:
Aahz wrote:
On Fri, Jun 19, 2009, Lie Ryan wrote:
In list/generator comprehension, currently we have no way to access the result of the expression and have to write something like this:
[f(x) for x in l if f(x) > 0]
if f() is heavy or nonpure (i.e. have side effects), calling f() twice might be undesirable. Listcomps and genexps are like lambdas: run up against their limits and you should switch to a regular for loop or generator. I think of it not as limitation but as an odd gap in functionality. I think having the semantics that the filtering is done after the expression part would be much more useful than the current behavior (filtering before expression).
The point of the filtering is to avoid needlessly calculating a potentially expensive expression only to throw it away.
If you want expression first, then filter, you can get that already in a oneliner:
filter(lambda x: x > 0, [f(x) for x in seq])
Don't create new syntax when there are perfectly good functions that do the job already.
That's ugly because of the same reason for using map(): [y for y in map(lambda x: f(x), seq) if y > 0]
or nested comprehension: [y for y in (f(x) for x in seq) if y > 0]
On Sat, 20 Jun 2009 08:31:26 am Lie Ryan wrote:
If you want expression first, then filter, you can get that already in a oneliner:
filter(lambda x: x > 0, [f(x) for x in seq])
Don't create new syntax when there are perfectly good functions that do the job already.
That's ugly because of the same reason for using map(): [y for y in map(lambda x: f(x), seq) if y > 0]
You don't like lambda? Fine, define an external function first. Then you can write:
filter(pred, (f(x) for x in seq))
There's no violation of DRY, there's no redundancy, there's no lambda, there's no "y" variable needed. What's ugly about it?
or nested comprehension: [y for y in (f(x) for x in seq) if y > 0]
You seem to be labouring under the misapprehension that anything that requires two steps instead of one is "ugly". I find the nested comprehension perfectly readable, although for more complicated cases I'd split it into two explicit steps. It is (almost) completely general, covering both filtering on both input args and output args:
gen = (3x**25x+4 for x in seq if x % 3 != 2) result = [y for y in gen if 3 < y < 3]
The only case it doesn't cover is where the second filter depends on the value of x, and even that can be covered with a tiny bit more work:
gen = ((x, 3x**25x+4) for x in seq if x % 3 != 2) result = [y[1] for y in gen if y[0] < y[1] < y[0]]
It requires no new syntax, no changes to the behaviour of list comps, no new meaning on "as", it's understandable and readable.
Compare your suggestion:
[3x**25x+4 as y for x in seq if (x % 3 != 2) and (x < y < x)]
Disadvantages:
Advantages:
 Steven D'Aprano
Steven D'Aprano wrote:
<snip>
The only case it doesn't cover is where the second filter depends on the value of x, and even that can be covered with a tiny bit more work:
gen = ((x, 3x**25x+4) for x in seq if x % 3 != 2) result = [y[1] for y in gen if y[0] < y[1] < y[0]]
It requires no new syntax, no changes to the behaviour of list comps, no new meaning on "as", it's understandable and readable.
Compare your suggestion:
[3x**25x+4 as y for x in seq if (x % 3 != 2) and (x < y < x)]
For me, this one is much clearer, understandable, and readable than y[0] and y[1]; and you still have the option to split them if you think y[0] and y[1] is better.
Disadvantages:
"as" is already used for renaming keyword in "with" and "import" statement, so I don't think it actually creates any more meaning that we don't already have.
Lie Ryan lie.1296@gmail.com writes:
Steven D'Aprano wrote:
<snip>
The only case it doesn't cover is where the second filter depends on the value of x, and even that can be covered with a tiny bit more work:
gen = ((x, 3x**25x+4) for x in seq if x % 3 != 2) result = [y[1] for y in gen if y[0] < y[1] < y[0]]
It requires no new syntax, no changes to the behaviour of list comps, no new meaning on "as", it's understandable and readable.
I think it would be more readable without index references, but instead using tuple unpacking::
gen = ((x, 3*x**25*x+4) for x in seq if x % 3 != 2)
result = [b for (a, b) in gen if a < b < a]
It can even be done as a single expression without (IMO) significantly affecting readability::
result = [
b for (a, b) in
((x, 3*x**25*x+4) for x in seq if x % 3 != 2)
if a < b < a]
Compare your suggestion:
[3x**25x+4 as y for x in seq if (x % 3 != 2) and (x < y < x)]
For me, this one is much clearer, understandable, and readable than y[0] and y[1]; and you still have the option to split them if you think y[0] and y[1] is better.
I hope you'll agree that my above suggestion retains this, without needing any new syntax.
 \ “If you go to a costume party at your boss's house, wouldn't  `\ you think a good costume would be to dress up like the boss's  _o__) wife? Trust me, it's not.” —Jack Handey  Ben Finney
Ben Finney wrote:
Lie Ryan lie.1296@gmail.com writes:
Steven D'Aprano wrote:
<snip>
The only case it doesn't cover is where the second filter depends on the value of x, and even that can be covered with a tiny bit more work:
gen = ((x, 3x**25x+4) for x in seq if x % 3 != 2) result = [y[1] for y in gen if y[0] < y[1] < y[0]]
It requires no new syntax, no changes to the behaviour of list comps, no new meaning on "as", it's understandable and readable.
I think it would be more readable without index references, but instead using tuple unpacking::
gen = ((x, 3*x**25*x+4) for x in seq if x % 3 != 2)
result = [b for (a, b) in gen if a < b < a]
It can even be done as a single expression without (IMO) significantly affecting readability::
result = [
b for (a, b) in
((x, 3*x**25*x+4) for x in seq if x % 3 != 2)
if a < b < a]
IMHO, when a comprehension requires more than a single line, it should turn into explicit loop.
<snip>What about where/let expression? [(y, y) for x in some_list if y < 0 where y = f(x)]
On Sun, Jun 21, 2009 at 10:36 AM, Lie Ryanlie.1296@gmail.com wrote:
Ben Finney wrote:
Lie Ryan lie.1296@gmail.com writes:
Steven D'Aprano wrote:
<snip>
The only case it doesn't cover is where the second filter depends on the value of x, and even that can be covered with a tiny bit more work:
gen = ((x, 3x**25x+4) for x in seq if x % 3 != 2) result = [y[1] for y in gen if y[0] < y[1] < y[0]]
It requires no new syntax, no changes to the behaviour of list comps, no new meaning on "as", it's understandable and readable.
I think it would be more readable without index references, but instead using tuple unpacking::
gen = ((x, 3x**25x+4) for x in seq if x % 3 != 2) result = [b for (a, b) in gen if a < b < a]
It can even be done as a single expression without (IMO) significantly affecting readability::
result = [ b for (a, b) in ((x, 3x**25x+4) for x in seq if x % 3 != 2) if a < b < a]
IMHO, when a comprehension requires more than a single line, it should turn into explicit loop.
<snip>Pythonideas mailing list Pythonideas@python.org http://mail.python.org/mailman/listinfo/pythonideas
 С уважением, Андрей Попп. +7 911 740 24 91
On Sun, Jun 21, 2009 at 10:36 AM, Lie Ryanlie.1296@gmail.com wrote:
Ben Finney wrote:
Lie Ryan lie.1296@gmail.com writes:
Steven D'Aprano wrote:
<snip>
The only case it doesn't cover is where the second filter depends on the value of x, and even that can be covered with a tiny bit more work:
gen = ((x, 3x**25x+4) for x in seq if x % 3 != 2) result = [y[1] for y in gen if y[0] < y[1] < y[0]]
It requires no new syntax, no changes to the behaviour of list comps, no new meaning on "as", it's understandable and readable.
I think it would be more readable without index references, but instead using tuple unpacking::
gen = ((x, 3x**25x+4) for x in seq if x % 3 != 2) result = [b for (a, b) in gen if a < b < a]
It can even be done as a single expression without (IMO) significantly affecting readability::
result = [ b for (a, b) in ((x, 3x**25x+4) for x in seq if x % 3 != 2) if a < b < a]
IMHO, when a comprehension requires more than a single line, it should turn into explicit loop.
<snip>On Sun, Jun 21, 2009 at 1:54 AM, Andrey Popp8mayday@gmail.com wrote: What about where/let expression?
С уважением, Андрей Попп. +7 911 740 24 91
(A) Please don't toppost. (http://en.wikipedia.org/wiki/Toppost) (B) That has the distinct disadvantage of adding a new keyword. I instead prefer the "as" version of the proposal for this reason.
Cheers,
On Jun 21, 2009 1:06pm, Chris Rebert pyideas@rebertia.com wrote:
On Sun, Jun 21, 2009 at 10:36 AM, Lie Ryanlie.1296@gmail.com> wrote:
Ben Finney wrote:
Lie Ryan lie.1296@gmail.com> writes:
>
Steven D'Aprano wrote:
>
The only case it doesn't cover is where the second filter depends on
the value of x, and even that can be covered with a tiny bit more
work:
>
gen = ((x, 3x**25x+4) for x in seq if x % 3 != 2)
result = [y[1] for y in gen if y[0]
It requires no new syntax, no changes to the behaviour of list
comps, no new meaning on "as", it's understandable and readable.
>
I think it would be more readable without index
references, but
instead
using tuple unpacking::
>
gen = ((x, 3x**25x+4) for x in seq if x % 3 != 2)
result = [b for (a, b) in gen if a
It can even be done as a single expression without (IMO) significantly
affecting readability::
>
result = [
b for (a, b) in
((x, 3x**25x+4) for x in seq if x % 3 != 2)
if a
IMHO, when a comprehension requires more than a single line, it should
turn into explicit loop.
>
>
>
On Sun, Jun 21, 2009 at 1:54 AM, Andrey Popp8mayday@gmail.com> wrote:
What about where/let expression?
С уважением, Андрей Попп.
+7 911 740 24 91
(A) Please don't toppost. (http://en.wikipedia.org/wiki/Toppost)
(B) That has the distinct disadvantage of adding a new keyword. I
instead prefer the "as" version of the proposal for this reason.
Cheers,
Chris

(A) Sorry
(B) There is no difference, except "where" is widely used in othe
languages. Anyway, I think that "where" like functionality would be useful
in list comprehensions, lambdas...
2009/6/21 Lie Ryan lie.1296@gmail.com:
It can even be done as a single expression without (IMO) significantly affecting readability::
result = [ b for (a, b) in ((x, 3x**25x+4) for x in seq if x % 3 != 2) if a < b < a]
IMHO, when a comprehension requires more than a single line, it should turn into explicit loop.
Hang on  isn't the whole point of this thread that, in your opinion, when a comprehension gets complex, it requires new syntax? :)
Paul.
Steven D'Aprano wrote:
On Sat, 20 Jun 2009 08:31:26 am Lie Ryan wrote:
You don't like lambda? Fine, define an external function first. Then you can write:
filter(pred, (f(x) for x in seq))
There's no violation of DRY, there's no redundancy, there's no lambda, there's no "y" variable needed. What's ugly about it?
I think its great and that it kills any justification for the proposal.
tjr
Terry Reedy wrote:
Steven D'Aprano wrote:
On Sat, 20 Jun 2009 08:31:26 am Lie Ryan wrote:
You don't like lambda? Fine, define an external function first. Then you can write:
filter(pred, (f(x) for x in seq))
There's no violation of DRY, there's no redundancy, there's no lambda, there's no "y" variable needed. What's ugly about it?
I think its great and that it kills any justification for the proposal.
tjr
I hate it. It mixes map/filter style and comprehension style; and the fact it does so in a single line only makes it worse. Not that it would be any better in two lines.
Lie Ryan schrieb:
Terry Reedy wrote:
Steven D'Aprano wrote:
On Sat, 20 Jun 2009 08:31:26 am Lie Ryan wrote:
You don't like lambda? Fine, define an external function first. Then you can write:
filter(pred, (f(x) for x in seq))
There's no violation of DRY, there's no redundancy, there's no lambda, there's no "y" variable needed. What's ugly about it?
I think its great and that it kills any justification for the proposal.
tjr
I hate it. It mixes map/filter style and comprehension style; and the fact it does so in a single line only makes it worse. Not that it would be any better in two lines.
Taking this further, using only map/filter style like this
filter(pred, map(f, seq))
takes two steps. Why is it so bad that doing it in a listcomp
(el for el in (f(y) for y in seq) if el > 2)
takes two steps as well?
Georg
 Thus spake the Lord: Thou shalt indent with four spaces. No more, no less. Four shall be the number of spaces thou shalt indent, and the number of thy indenting shall be four. Eight shalt thou not indent, nor either indent thou two, excepting that thou then proceed to four. Tabs are right out.
Georg Brandl wrote:
Lie Ryan schrieb:
Terry Reedy wrote:
Steven D'Aprano wrote:
On Sat, 20 Jun 2009 08:31:26 am Lie Ryan wrote: You don't like lambda? Fine, define an external function first. Then you can write:
filter(pred, (f(x) for x in seq))
There's no violation of DRY, there's no redundancy, there's no lambda, there's no "y" variable needed. What's ugly about it? I think its great and that it kills any justification for the proposal.
tjr I hate it. It mixes map/filter style and comprehension style; and the fact it does so in a single line only makes it worse. Not that it would be any better in two lines.
Taking this further, using only map/filter style like this
filter(pred, map(f, seq))
takes two steps. Why is it so bad that doing it in a listcomp
(el for el in (f(y) for y in seq) if el > 2)
takes two steps as well?
Georg
Comprehension, by its nature, is map+filter in a single expression. Nested comprehension is (map+filter)+(map+filter).
(where + is some sort of function composition)
The proposal enables comprehension to become filter+map+filter, map+filter, filter+map, or maponly; eliminating the redundant map in (map+filter)+(map+filter).
The filter() and map() functions are two separate function in the first place, so there is no redundancy in it.
Mixing the two styles is ugly since it means you have to think in two separate (though related) paradigms.
Lie Ryan writes:
The proposal enables comprehension to become filter+map+filter, map+filter, filter+map, or maponly; eliminating the redundant map in (map+filter)+(map+filter).
The problem with the proposal is that that is all it does. I don't see how you plan to disambiguate in cases where the desired operation "really is" (map+filter)+(map+filter). So what you're stuck at is "I want this one operation to be a oneliner." The reply to that is "not every twoline function needs to have special syntax."
Unless you can generalize this proposal to handle more general lambdas in a beautiful and Pythonic way, you've already been offered two obvious and nice ways to do it, and another obvious way that is an "ugly" mixed metaphor. All of the other idioms do generalize. We just spent several years decluttering Python 3, it's too soon to start cluttering it up again, no matter how beautiful it makes this special case.
And I happen to think Ben's iterated generator comprehension is the most beautiful of the lot. YMMV of course but so does a that of a lot of other people; getting a consensus for new syntax is going to be impossible if you don't generalize the proposal.
Stephen J. Turnbull wrote:
Lie Ryan writes:
The proposal enables comprehension to become filter+map+filter, map+filter, filter+map, or maponly; eliminating the redundant map in (map+filter)+(map+filter).
The problem with the proposal is that that is all it does. I don't see how you plan to disambiguate in cases where the desired operation "really is" (map+filter)+(map+filter). So what you're stuck at is "I want this one operation to be a oneliner." The reply to that is "not every twoline function needs to have special syntax."
The regular map+filter is still available by not using the as
keyword
(or by not calling F). Thus when what you really wanted is two maps, you
need to use two comprehensions. The number of maps should == The number
of comprehension; currently it is not always possible to do so, when the
assumed map and filter ordering doesn't match our required ordering.
Lie Ryan writes:
The regular map+filter is still available by not
using the as
keyword
(or by not calling F). Thus when what you really wanted is two maps, you
need to use two comprehensions. The number of maps should == The number
of comprehension; currently it is not always possible to do so, when the
assumed map and filter ordering doesn't match our required ordering.
I understand that; the first part is a trivial consequence of backward compatibility, and the second you've been at pains to explain already. I'm not trying to say you're wrong. The appeal of the proposed syntax in the particular case is obvious.
Admittedly, I personally don't find it particularly useful. I don't have any problem at all with decomposing what you consider to be a single comprehension into a pipeline of generators. It's efficient and elegant, and it's not clear to me that your construct can generate better byte code than Ben's nested comprehensions. If not, your claim that "this is conceptually a single comprehension, why break it into two or more" seems to me to be founded on quicksand. But that's beside the point, I don't have to like all the constructs that other people find useful. Even Guido has allowed things into Python that he personally dislikes quite a bit.
I'm saying it's my impression that it will be insufficient. It's like if somebody suggested introducing a unary operator "" to denote "squared". That's just not useful enough, while a binary operator "" for "power" is useful enough to have been added ages ago.
In other words, that kind of logic hasn't been able to justify proliferation of syntax in the more than 5 years I've been following PythonDev (and now PythonIdeas). It only works when the new syntax is sufficiently comprehensive to replace "all the old uglies" in some sense. Even if you can't clear the hurdle in one bound, you need to aim at something like "getting rid of all lambda/external function definitions in comprehensions".
Lie Ryan schrieb:
I hate it. It mixes map/filter style and comprehension style; and the fact it does so in a single line only makes it worse. Not that it would be any better in two lines.
Taking this further, using only map/filter style like this
filter(pred, map(f, seq))
takes two steps. Why is it so bad that doing it in a listcomp
(el for el in (f(y) for y in seq) if el > 2)
takes two steps as well?
Georg
Comprehension, by its nature, is map+filter in a single expression.
Let's stick with "+" for function composition. Then comprehension is,
as you say, map + filter
(map after filter). It is not
filter + map
(filter after map), which is what would be needed in
the case discussed in this thread. In the functional waym you can of
course combine map and filter in the order you like.
Nested comprehension is (map+filter)+(map+filter).
Yes, and in this case, we use it as (id+filter) + (map+id)
, which
is
the easiest way to build a filter + map
with the map + filter
building block.
Mixing the two styles is ugly since it means you have to think in two separate (though related) paradigms.
I mentally translate map and filter into comprehensions anyway (or maybe rather both translate into the same more abstract thing), so I don't see it as ugly.
Georg
Lie Ryan schrieb:
Steven D'Aprano wrote:
On Fri, 19 Jun 2009 05:39:32 pm Lie Ryan wrote:
Aahz wrote:
On Fri, Jun 19, 2009, Lie Ryan wrote:
In list/generator comprehension, currently we have no way to access the result of the expression and have to write something like this:
[f(x) for x in l if f(x) > 0]
if f() is heavy or nonpure (i.e. have side effects), calling f() twice might be undesirable. Listcomps and genexps are like lambdas: run up against their limits and you should switch to a regular for loop or generator. I think of it not as limitation but as an odd gap in functionality. I think having the semantics that the filtering is done after the expression part would be much more useful than the current behavior (filtering before expression).
The point of the filtering is to avoid needlessly calculating a potentially expensive expression only to throw it away.
If you want expression first, then filter, you can get that already in a oneliner:
filter(lambda x: x > 0, [f(x) for x in seq])
Don't create new syntax when there are perfectly good functions that do the job already.
That's ugly because of the same reason for using map(): [y for y in map(lambda x: f(x), seq) if y > 0]
Especially if f is already a handy callable of one argument, no need to use a lambda.
Georg
 Thus spake the Lord: Thou shalt indent with four spaces. No more, no less. Four shall be the number of spaces thou shalt indent, and the number of thy indenting shall be four. Eight shalt thou not indent, nor either indent thou two, excepting that thou then proceed to four. Tabs are right out.
Georg Brandl wrote:
Lie Ryan schrieb:
That's ugly because of the same reason for using map(): [y for y in map(lambda x: f(x), seq) if y > 0]
Especially if f is already a handy callable of one argument, no need to use a lambda.
Ahh... yes. Sometimes I actually meant f(x) to be a substitute to any expression (both simple: x**2 or complex: foo(x))
but well, I didn't actually see that one...
2009/6/18 Lie Ryan lie.1296@gmail.com:
In list/generator comprehension, currently we have no way to access the result of the expression and have to write something like this:
[f(x) for x in l if f(x) > 0]
if f() is heavy or nonpure (i.e. have side effects), calling f() twice might be undesirable.
[y for y in (f(x) for x in l) if y > 0]
But as Aahz says, if it's too complex, use an explicit loop. Not everything needs to be a oneliner.
Paul
Paul Moore wrote:
2009/6/18 Lie Ryan lie.1296@gmail.com:
In list/generator comprehension, currently we have no way to access the result of the expression and have to write something like this:
[f(x) for x in l if f(x) > 0]
if f() is heavy or nonpure (i.e. have side effects), calling f() twice might be undesirable.
[y for y in (f(x) for x in l) if y > 0]
But as Aahz says, if it's too complex, use an explicit loop. Not everything needs to be a oneliner.
Paul
Avoiding a nested list comprehension is exactly the motivation for the idea.
[Lie Ryan]
In list/generator comprehension, currently we have no way to access the result of the expression and have to write something like this:
[f(x) for x in l if f(x) > 0]
if f() is heavy or nonpure (i.e. have side effects), calling f() twice might be undesirable.
[x for x in map(f, l) if x > 0]
Raymond
Lie Ryan wrote:
In list/generator comprehension, currently we have no way to access the result of the expression and have to write something like this:
[f(x) for x in l if f(x) > 0]
if f() is heavy or nonpure (i.e. have side effects), calling f() twice might be undesirable.
Even if f() is not a function such as
[x + 1 for x in l if x + 1 > 0]
it looks ugly since we're repeating ourself.
We can work around it like this:
[y for y in (f(x) for x in l) if y > 0]
but then we have an unnecessary nested loop comprehension.
I'm suggesting about something like:
[f(x) for x in l if @ > 0]
where @ is the result of the listcomp's expression (i.e. f(x))
Personally, I don't like the use of symbols like @, as python is not perl. I'm still thinking of a better syntax/approach and is open for suggestion.
What do you guys think?
IMO this is premature optimization. (I know that's an annoying thing to say, but bear with me...)
Just using [f(x) for x in nums if f(x) > 0] is the most readable and obvious option. I think the case where such a line of code actually needs to be optimized is rare, and on there rare occasions using a slightly less readable variant is reasonable (along with an insightful comment).
In other words, from my experience all we would gain from the proposed new syntax is making such premature optimization easier, at the cost of less readable code and more complex syntax.
On Fri, Jun 19, 2009 at 7:34 AM, Tal Einattaleinat@gmail.com wrote:
Just using [f(x) for x in nums if f(x) > 0] is the most readable and obvious option.
I would often prefer to break it into two steps:
temp = (f(x) for x in nums)
results = [e for e in temp if e>0]
Others will dislike the extra line and temp var, which is one reason it isn't among the several solutions previously suggested. Are these differences big enough (or the solutions obscure enough) that the variation is itself a cost of the current situation?
jJ
On Fri, Jun 19, 2009 at 4:45 PM, Jim Jewettjimjjewett@gmail.com wrote:
On Fri, Jun 19, 2009 at 7:34 AM, Tal Einattaleinat@gmail.com wrote:
Just using [f(x) for x in nums if f(x) > 0] is the most readable and obvious option.
I would often prefer to break it into two steps:
temp = (f(x) for x in nums) results = [e for e in temp if e>0]
I sometimes find myself doing that too. That's probably more readable than what I wrote :)
Others will dislike the extra line and temp var, which is one reason it isn't among the several solutions previously suggested.
I sometimes avoid the temporary variable by using the same one twice, e.g.: results = (f(x) for x in nums) results = [res for res in results if res > 0]
In the above example the second line is just filtering the results, and I feel this idiom conveys the idea pretty well.
Le Fri, 19 Jun 2009 09:45:08 0400, Jim Jewett jimjjewett@gmail.com s'exprima ainsi:
On Fri, Jun 19, 2009 at 7:34 AM, Tal Einattaleinat@gmail.com wrote:
Just using [f(x) for x in nums if f(x) > 0] is the most readable and obvious option.
I would often prefer to break it into two steps:
temp = (f(x) for x in nums)
results = [e for e in temp if e>0]
Others will dislike the extra line and temp var, which is one reason it isn't among the several solutions previously suggested. Are these differences big enough (or the solutions obscure enough) that the variation is itself a cost of the current situation?
Ditto for me.
A list comp with both computation and filtering is for me two ideas, two steps, so I write two lines anyway. This also has the advantage to disambiguate the order issue (computation or filter first?) and there is no risk of double sideeffect (which anyway I never use, but who knows...).
la vita e estrany
You could write: [xy < l, x < [f(y)], x > 0]
Oh, wait. Thats Haskell. And even in haskell you would write: [xx < map f l, x > 0]
In Python you can write: [x for x in map(f,l) if x > 0]
In Python 2.x you may want to write: from itertools import imap [x for x in imap(f,l) if x > 0]
A more SQL like approach that would fit somewhat with pythons syntax would be (as you can see its exactly the same lengths as the above but needs a new name): [f(x) as y for x in l if y > 0]
Because in SQL you can write (IIRC): select f(x) as y from l where y > 0;
Maybe something like .Nets LINQ would be a nice idea to integrate in python?
panzi
Lie Ryan wrote:
In list/generator comprehension, currently we have no way to access the result of the expression and have to write something like this:
[f(x) for x in l if f(x) > 0]
if f() is heavy or nonpure (i.e. have side effects), calling f() twice might be undesirable.
Even if f() is not a function such as
[x + 1 for x in l if x + 1 > 0]
it looks ugly since we're repeating ourself.
We can work around it like this:
[y for y in (f(x) for x in l) if y > 0]
but then we have an unnecessary nested loop comprehension.
I'm suggesting about something like:
[f(x) for x in l if @ > 0]
where @ is the result of the listcomp's expression (i.e. f(x))
Personally, I don't like the use of symbols like @, as python is not perl. I'm still thinking of a better syntax/approach and is open for suggestion.
What do you guys think?
On Fri, Jun 19, 2009 at 10:54 AM, Mathias Panzenböckgrosser.meister.morti@gmx.net wrote:
You could write: [xy < l, x < [f(y)], x > 0]
Oh, wait. Thats Haskell. And even in haskell you would write: [xx < map f l, x > 0]
In Python you can write: [x for x in map(f,l) if x > 0]
In Python 2.x you may want to write: from itertools import imap [x for x in imap(f,l) if x > 0]
A more SQL like approach that would fit somewhat with pythons syntax would be (as you can see its exactly the same lengths as the above but needs a new name): [f(x) as y for x in l if y > 0]
Because in SQL you can write (IIRC): select f(x) as y from l where y > 0;
Maybe something like .Nets LINQ would be a nice idea to integrate in python?
Comprehensions and generator expressions already give us most of the
LINQ functionality. Add in list()
and the ability to .sort()
lists
with a key
argument and you have the entire thing, except for the
one corner case being discussed. Unless I've overlooked something...
Cheers,
Chris Rebert wrote:
On Fri, Jun 19, 2009 at 10:54 AM, Mathias Panzenböckgrosser.meister.morti@gmx.net wrote:
You could write: [xy < l, x < [f(y)], x > 0]
Oh, wait. Thats Haskell. And even in haskell you would write: [xx < map f l, x > 0]
In Python you can write: [x for x in map(f,l) if x > 0]
In Python 2.x you may want to write: from itertools import imap [x for x in imap(f,l) if x > 0]
A more SQL like approach that would fit somewhat with pythons syntax would be (as you can see its exactly the same lengths as the above but needs a new name): [f(x) as y for x in l if y > 0]
Because in SQL you can write (IIRC): select f(x) as y from l where y > 0;
Maybe something like .Nets LINQ would be a nice idea to integrate in python?
Comprehensions and generator expressions already give us most of the
LINQ functionality. Add in list()
and the ability to .sort()
lists
with a key
argument and you have the entire thing, except for the
one corner case being discussed. Unless I've overlooked something...
Yes: With LINQ its possible to build a query object out of an LINQ expression instead of evaluating it eagerly. This is used primarily to generate SQL code while still using syntax native to the host language (C#) and preserving type safety (ok the later cannot be done in python).
panzi
On Fri, Jun 19, 2009 at 12:56 PM, Mathias Panzenböckgrosser.meister.morti@gmx.net wrote:
Chris Rebert wrote:
On Fri, Jun 19, 2009 at 10:54 AM, Mathias Panzenböckgrosser.meister.morti@gmx.net wrote:
You could write: [xy < l, x < [f(y)], x > 0]
Oh, wait. Thats Haskell. And even in haskell you would write: [xx < map f l, x > 0]
In Python you can write: [x for x in map(f,l) if x > 0]
In Python 2.x you may want to write: from itertools import imap [x for x in imap(f,l) if x > 0]
A more SQL like approach that would fit somewhat with pythons syntax would be (as you can see its exactly the same lengths as the above but needs a new name): [f(x) as y for x in l if y > 0]
Because in SQL you can write (IIRC): select f(x) as y from l where y > 0;
Maybe something like .Nets LINQ would be a nice idea to integrate in python?
Comprehensions and generator expressions already give us most of the
LINQ functionality. Add in list()
and the ability to .sort()
lists
with a key
argument and you have the entire thing, except for the
one corner case being discussed. Unless I've overlooked something...
Yes: With LINQ its possible to build a query object out of an LINQ expression instead of evaluating it eagerly. This is used primarily to generate SQL code while still using syntax native to the host language (C#) and preserving type safety (ok the later cannot be done in python).
One could probably hack that part together with lambdas, the ast module, and some black magic though. And are there any use cases besides SQL? But point taken.
Cheers,
Chris Rebert wrote:
On Fri, Jun 19, 2009 at 12:56 PM, Mathias Panzenböckgrosser.meister.morti@gmx.net wrote:
Chris Rebert wrote:
Comprehensions and generator expressions already
give us most of the
LINQ functionality. Add in list()
and the ability to .sort()
lists
with a key
argument and you have the entire thing, except for the
one corner case being discussed. Unless I've overlooked something...
Yes: With LINQ its possible to build a query object out of an LINQ
expression instead of evaluating it eagerly. This is used primarily to
generate SQL code while still using syntax native to the host language (C#)
and preserving type safety (ok the later cannot be done in python).
One could probably hack that part together with lambdas, the ast module, and some black magic though. And are there any use cases besides SQL?
Yes: Queries on XML data. So you have the exact same Syntax for queries on simple lists, SQL databases and XML files (but yes, using LINGQ for XML is still much more to write than using something like XPath). I think you can also add your own backends if you like (e.g. for yaml?). And it's all native syntax (no limits on expressiveness and no problems concerning string escaping etc.).
panzi
On 18 Jun 2009, at 21:19, Lie Ryan wrote:
In list/generator comprehension, currently we have no
way to access
the
result of the expression and have to write something like this:
[f(x) for x in l if f(x) > 0]
if f() is heavy or nonpure (i.e. have side effects), calling f()
twice
might be undesirable.
Even if f() is not a function such as
[x + 1 for x in l if x + 1 > 0]
it looks ugly since we're repeating ourself.
We can work around it like this:
[y for y in (f(x) for x in l) if y > 0]
but then we have an unnecessary nested loop comprehension
You can write:
[y for x in l for y in [f(x)] if y > 0]
Which is even worse ;)
 Arnaud