[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): ...
*wink*
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):
print(message)
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.
[Chris]
> >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()
[MRAB]
> 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
possible.
But, whether you call it "every" or "consume", the code still looks
misleading:
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.
--
Steve
More information about the Python-ideas
mailing list