[Python-ideas] BUG in standard while statement

Steven D'Aprano steve at pearwood.info
Fri Sep 11 04:39:23 CEST 2015

On Thu, Sep 10, 2015 at 11:12:39PM +0100, MRAB wrote:
> On 2015-09-10 20:04, Chris Barker wrote:
> >however, he did bring up a python-idea worthy general topic:
> >
> >Sometimes you want to iterate without doing anything with the results of
> >the iteration.
> >
> >So the obvious is his example -- iterate N times:
> >
> >for i in range(N):
> >     do_something
> >
> >but you may need to look into the code (probably more than one line) to
> >see if i is used for anything.

Solution is obvious:

for throw_away_variable_not_used_for_anythng in range(N): ...


Just use one of the usual conventions for throw-away variables: call it 
_ or whocares. But, why do you care so much about whether i is 
being used for something?

Today, you have:

    for whocares in range(10):

Next week, you decide you need to number them, now you do care 
about the loop variable:

    for whocares in range(10):
        print(whocares, message)

Having a loop variable that may remain unused is not exactly a big deal.

> >However, I've found myself wanting a "make nothing comprehension". For
> >some reason, I find myself frequently following a pattern where I want
> >to call the same method on all the objects in a sequence:
> >
> >for obj in a_sequence:
> >     obj.a_method()
> >
> >but I like the compactness of comprehensions, so I do:
> >
> >[obj.a_method() for obj in a_sequence]

Ew, ew, ew, ew. You're calling the method for its side-effects, not its 
return result (which is probably None, but might not be). Turning it 
into a list comp is abuse of comprehensions: you're collecting the 
return results, potentially creating an enormous list, which you 
don't actually want and immediately throw away.

Just write it as a one-liner for-loop, which is *more* compact (by 
exactly one character) as the list comp):

[obj.a_method() for obj in a_sequence]
for obj in a_sequence: obj.a_method()

> You could use a generator expression with a function that discards the 
> results:
> def every(iterable):
>     for _ in iterable:
>         pass
> every(obj.a_method() for obj in a_sequence)

If you're going to do such a horrid thing, at least name it accurately. 
"every" sounds like a synonym for the built-in "all". A more accurate 
name would be "consume", as in consuming the iterator, and I seem to 
recall that there's a recipe in the itertools docs to do that as fast as 

But, whether you call it "every" or "consume", the code still looks 

every(obj.a_method() for obj in a_sequence)

looks like you care about the return results of a_method, but you don't. 
List comps and generator expressions are for cases where you care about 
the expression's result.


More information about the Python-ideas mailing list