Issue 30471: "as" keyword in comprehensions (original) (raw)

Currently, the "as" keyword in supported in import and with statements to bind an object to a name. I think it would be nice to have the same functionality in list/dict/etc. comprehensions as well.

Rationale: as I understand, comprehensions are preferred over map/filter + lambdas for creating modified versions of sequences (etc.) in Python. They are indeed useful for replacing map, filter, or map(filter); however, filter(map) is currently not supported. This is not an unusual use-case, as the two examples below show. It is also evident that they are very wordy with lambdas, and could be much clearer with comprehensions:

with open(file) as inf:
    lines = list(filter(lambda l: l, map(lambda line: line.strip(), inf)))
items = dict(filter(lambda kv: kv[1] > 5,
                    map(lambda kv: kv[0], len(kv[1]), d.items())))

Currently the only way to do this with comprehensions are:

with open(file) as inf:
    lines = [l for l in (line.strip() for line in inf) if l]
items = {k: v for k, v in ((k, len(v)) for k, v in d.items()) if v > 5)}

, or

items = {k: len(v) for k, v in d.items() if len(v) > 5}

The first option is as unwieldy and unreadable as the code with lambdas, while the second is ineffective as it calls len() twice (and of course here len() is just a placeholder for a potentially heavy operation).

I propose to allow the "as" keyword in comprehensions as well to bind the result of an operation in the output expression to a name that could be used in the optional predicate. In other words, provide a let-like functionality. Like so:

with open(file) as inf:
    lines = [line.strip() as l for line in inf if l]
items = {(k, len(v) as lenv) for k, v in d.items() if lenv > 5}

As Brett says, the place to propose this is on python-ideas.

I'm going to mark it here as closed/rejected because it will likely have to go through a lengthy process (possibly including a PEP) before having a chance of being accepted. Please don't take this as discouragement. It is just that the tracker is the wrong forum for the conversation to start.

On the plus side, the idea does seem like a nice convenience. On the minus side, we really like that inconveniences serve as a nudge to not put too much inside a list comprehension and use a regular for-loop instead. Also, Guido in the past has resisted similar suggestions for making assignments inside a while-loop conditional expression ("while (f.read(10) as block) != '': ...).

The truth is, I was thinking about going to the list, but according to PEP 42 (https://www.python.org/dev/peps/pep-0042/), this space was one of the places new features could be requested:

""" Note

This PEP has been rejected as obsolete. All new feature requests should either go to the Python bug tracker [1] or the python-ideas [2] mailing list. The rest of this document is retained for historical purposes only. """

Going to the list, then.