On Thu, Mar 23, 2006 at 05:27:48PM -0800, Guido van Rossum wrote: > On 3/23/06, Ian Bicking <[EMAIL PROTECTED]> wrote: > > Empty iterator or iterator that produced no items -- from the outside > > it's the same use case. > > I see it as an education issue. Because we have generators, the > iterator protocol can't be extended to support a test for emptiness -- > that's just not something that generators can be expected to support. > So yes, there's confusion, but there's no way to remove the confusion, > no matter how many times you repeat the usability issues. If we extend > the iterator protocol with a mandatory emptiness test API, that > excludes generators from being considered iterators, and the API > design question you have to ask is whether you want to support > generators.
90% of the time I don't know or care if I am using an iterable or an iterator. As Martelli pointed out in this thread, for the times when you don't care iterators are preferable on speed-and-space grounds. Most of the other 10% requires special testing for empty regardless of a list or iter. import csv import itertools as it # list way mycsv = list(csv.reader(open('foo.csv'))) header = mycsv[0] rows = mycsv[1:] for (d) in [dict(zip(header, row)) for (row) in rows]: # do stuff # iter way mycsv = csv.reader(open('foo.csv')) header = mycsv.next() for (d) in (dict(zip(header, row)) for (row) in mycsv): # do stuff For finger typing the two are a push, I'd give the iter version a slight edge in clarity. Both examples raise exceptions for empty files. Ian's and other's seem to prefer the readability of iterables for that exceptional case. > If you find the 'empty' flag pattern too ugly, you can always write a > helper class that takes an iterator and returns an object that > represents the same iterator, but sometimes buffers one element. But > the buffering violates the coroutine-ish properties of generators, so > it should not be the only (or even the default) way to access > generators. [snip Guido's peek ahead iterator class] My good sir, you have stopped at mere hack when a depraved hack was available. Peek-ahead isn't necessary for this one, pep 343 is. from __future__ import pep343_is_implemented with iter_or_false(it) as test: for (val) in test: print val else: print "break wasn't called" if (not test): print "it was empty!" # implementation of iter_or_false (tested!) import itertools class iter_or_false(object): def __init__(self, iterable): self.it = iter(iterable) self.empty = True def __nonzero__(self): return not self.empty def __context__(self): return self def __exit__(self, *info): return False def __enter__(self): return self def __iter__(self): return self def next(self): val = self.it.next() self.empty = False return val I agree it is much better to put the smarts in the SQL result class (grow a __nonzero__ method and a ob.rows iterator) than to force it into a general case But if it absolutely must be tacked-on ... -jackdied _______________________________________________ Python-3000 mailing list Python-3000@python.org http://mail.python.org/mailman/listinfo/python-3000 Unsubscribe: http://mail.python.org/mailman/options/python-3000/archive%40mail-archive.com