[Python-Dev] The `for y in [x]` idiom in comprehensions
Steven D'Aprano
steve at pearwood.info
Sat Feb 24 00:20:16 EST 2018
On Fri, Feb 23, 2018 at 11:23:04AM -0800, Chris Barker wrote:
> But I still think the original:
>
> [g(y) for x in range(5) for y in [f(x)]]
>
> Is always going to be confusing to read. Though I do agree that it's not
> too bad when you unpack it into for loops:
>
> In [89]: for x in range(5):
> ...: for y in [f(x)]:
> ...: l.append(g(y))
I think we should distinguish between:
* actively confusing; and
* merely not obvious at a glance.
I acknowledge that this idiom is not obvious at a glance, but I don't
think this comes even close to actively confusing. As you say, once you
mentally unpack the loops it becomes clear.
Given a potentially expensive DRY violation like:
[(function(x), function(x)+1) for x in sequence]
there are at least five ways to solve it.
* Perhaps it doesn't need solving; if the DRY violation is trivial
enough, and the cost low enough, who cares?
* Re-write as a for-loop instead of a comprehension;
* Use a helper function:
def helper(x)
tmp = function(x)
return (tmp, tmp+1)
[helper(x) for x in sequence]
* Chain the operations:
[(a, a+1) for a in (function(x) for x in sequence)]
[(a, a+1) for a in map(function, sequence)]
* Use a second loop to get an assignment:
[(a, a+1) for x in sequence for a in [function(x)]]
I don't think we need to promote any one of the above as the One True
idiom. They're all simple, more-or-less obvious or at least
understandable, and deciding between them should be a matter of personal
choice and in-house style guides.
> BTW, would it be even a tiny bit more efficient to use a tuple in the inner
> loop?
>
> [g(y) for x in range(5) for y in (f(x),)]
The suggested patch will recognise both `y in (a,)` and `y in [a]` and
treat them the same as a direct assignment `y=a`.
But if you're writing cross-interpreter code which might run on older
versions of Python, or implementations which may not have this
optimization, you might prefer to micro-optimize by using a tuple.
--
Steve
More information about the Python-Dev
mailing list