Boolean tests [was Re: Attack a sacred Python Cow]

Carl Banks pavlovevidence at gmail.com
Wed Jul 30 00:52:52 EDT 2008


On Jul 29, 11:17 pm, Terry Reedy <tjre... at udel.edu> wrote:
> Carl Banks wrote:
> >> As I wrote in the second reply email I sent, check out my integer set
> >> recipe on ASPN (and to save you the search:  http://code.activestate.com/recipes/466286/).
>
> > Couple points:
>
> > 1. Any container type that returns a length that isn't exactly the
> > number of elements in it is broken.
> > 2. The need for __nonzero__ in this case depends on a limitation in
> > the language.
> > 3. On the other hand, I will concede that sometimes calculating len is
> > a lot more expensive than determining emptiness, and at a basic level
> > it's important to avoid these costs.  You have found a practical use
> > case for __nonzero__.
>
> I thought of another one: testing whether an iterator is 'empty' (will
> raise StopIteration on the next next() (3.0) call) or not.  As virtual
> collections, iterators generally have neither __len__ or __bool__.  But
> __bool__ (but only __bool__) can be added to any iterator by wrapping it
> with something like the following 3.0 code (not tested):
>
> class look_ahead_it():
>    def __init__(self, iterable):
>      self.it = iter(iterable)
>      self.fill_next()
>
>    def __iter__(self):
>      return self
>    def __next__(self):
>      tem = self.next
>      if tem is self.empty:
>        raise StopIteration
>      else:
>        self.fill_next()
>        return tem
>
>    empty = object()
>    def fill_next(self)
>      try:
>        self.next = next(self.it)
>      except StopIteration:
>        self.next = self.empty
>
>    def __bool__(self):
>      return self.next is not self.empty

Iterators are funny: if there's any reason you should not use "if x"
it's because of them.  Built-in iterators are always true, so if
you're writing a function that accepts an iterable you should never
use the "if x" to test whether it's empty, because it fails for a
whole class of iterables.

However, given that that wart exists, your example does work for "if
x" and not with "if len(x)!=0".

Then again, it really only works to accommodate faulty code, because
no code that expects an iterable should be using that test in the
first place.  (Unless you wrap every iterable as soon as you get it,
but then you're not bound to use __nonzero__.)


Carl Banks



More information about the Python-list mailing list