[Python-ideas] Function to return first(or last) true value from list
אלעזר
elazarg at gmail.com
Fri Feb 21 10:34:17 CET 2014
More information about the Python-ideas mailing list
Fri Feb 21 10:34:17 CET 2014
- Previous message: [Python-ideas] Function to return first(or last) true value from list
- Next message: [Python-ideas] Function to return first(or last) true value from list
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
What is the "classic" use case for next() raising StopIteration, to be silently caught ? We need __next__ to do so in for loops, but when do we need it in the functional form? Elazar 2014-02-21 11:25 GMT+02:00 Peter Otten <__peter__ at web.de>: > Oscar Benjamin wrote: > > > On 20 February 2014 22:38, אלעזר <elazarg at gmail.com> wrote: > >> > >> 2014-02-21 0:00 GMT+02:00 Steven D'Aprano <steve at pearwood.info>: > >>> > >>> On Thu, Feb 20, 2014 at 04:14:17PM +0000, Oscar Benjamin wrote: > >>> > > >>> > The thing is just that bare next is not something that's widely > >>> > recognised as being dangerous. I've seen examples of this kind of bug > >>> > in samples from many Python aficionados (including at least one from > >>> > you Terry). > >>> > >>> Why is it dangerous, and what kind of bug? > >>> > >>> If you're talking about the fact that next(it) can raise StopIteration, > >>> I think you are exaggerating the danger. Firstly, quite often you don't > >>> mind if it raises StopIteration, since that's what you would have done > >>> anyway. Secondly, I don't see why raising StopIteration is so much more > >>> dangerous than (say) IndexError or KeyError. > >>> > >> I had this bug just the other day. I did not plan for the empty case, > >> since it was obvious that the empty case is a bug, so I relied on the > >> exception being raised in this case. But I did not get the exception > >> since it was caught in a completely unrelated for loop. It took me a > >> while to figure out what's going on, and it would've taken even more for > >> someone else, not familiar with my assumption or with the whole > >> StopIteration thing (which I believe is the common case). An IndexError > >> or a KeyError would have been great in such a case. > > > > Exactly. The bug I had manifested in a StopIteration that was raised > > in a semi-deterministic (dependent on slowly varying data) fashion > > after ~1 hour of processing. Had it resulted in an IndexError I would > > have seen a traceback and could have fixed the bug within about 5 > > minutes. > > > > But StopIteration doesn't necessarily bubble up in the same way as > > other exceptions because it can be caught and silently supressed by a > > for loop (or any consumer of iterators). So instead of a traceback I > > had truncated output data. It took some time to discover and verify > > that the output data was truncated. Then it took some time rerunning > > the script under pdb which was no help since it couldn't latch into > > the suppressed exception. I assumed that it must be an exception but > > there were no try/except clauses anywhere in the code. Eventually I > > found it by peppering the code with: > > > > try: > > ... > > except Exception as e: > > import pdb; pdb.set_trace() > > > > It took most of a day for me to track that down instead of 5 minutes > > precisely because StopIteration is not like other exceptions. > > Admittedly I'd spot a similar bug much quicker now simply because I'm > > aware of the possibility. > > > > A simplified version of the bug is shown below: > > > > def itermerge(datasources): > > for source in datasources: > > iterator = iter(source) > > first = next(iterator) > > for item in iterator: > > yield first * item > > > > data = [ > > [1, 1, 2, 3], > > [1, 4, 5, 6], > > [], # Who put that there? > > [1, 7, 8, 9], > > ] > > > > for item in itermerge(data): > > print(item) > > > > If you run the above then you get: > > > > $ python tmp.py > > 1 > > 2 > > 3 > > 4 > > 5 > > 6 > > > > So the data is silently truncated at the empty iterable. > > > >> It is *very* similar to the "and or" story. > > I think the difference is that once you've learned the lesson you stop > using > `and...or` while you change your usage pattern for next() to minimal scopes > > def process_source(source): > it = iter(source) > first = next(it) > for item in it: > yield first * item > > def itermerge(sources): > for source in sources: > yield from process_source(source) > > > _______________________________________________ > Python-ideas mailing list > Python-ideas at python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.python.org/pipermail/python-ideas/attachments/20140221/e02bb227/attachment.html>
- Previous message: [Python-ideas] Function to return first(or last) true value from list
- Next message: [Python-ideas] Function to return first(or last) true value from list
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
More information about the Python-ideas mailing list