This small recipe enables truth value testing on iterables.
It is quite common to do things like:
if somesequence:
...
else:
...
Such constructs, that enter the if block if the sequence's got one or more elements and the else block if it's empty, work fine on non-lazy builtin sequences (lists, strings, tuples) and dictionaries as well, but doesn't necessarily work on generic iterables - most of them are always true regardless of their contents, since they're some kind of object. A classical example is generators, but such behaviour can be extended to any object implementing the Iterable interface.
Just wrap your iterable with this decorator and you'll get a truth-aware iterable which supports proper truth testing by doing a small first element prefetching and can then be used just like the original iterable.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | from itertools import chain
class TruthValueAwareIterable(object):
def __init__(self, iterable):
self._iterator = iter(iterable)
try:
self._head = [self._iterator.next()]
self._has_value = True
except StopIteration:
self._head = []
self._has_value = False
def __nonzero__(self):
return self._has_value
def __iter__(self):
return chain(self._head, self._iterator)
if __name__ == "__main__":
def integer_generator():
yield 1
yield 2
yield 3
assert not TruthValueAwareIterable(iter([]))
assert TruthValueAwareIterable(integer_generator())
assert list(TruthValueAwareIterable([])) == []
assert list(TruthValueAwareIterable(integer_generator())) == [1, 2, 3]
|
I like it.
which works fine on lists, but doesn't work on iterables
s/iterables/generators/g List is also an iterable. You mean generator, it's truth value is True despite it produces empty sequence.
As far I know in python 3.3 you could use
pavel: I mean what I wrote, you seem to look at it the other way round :-)
The iterable interface is generic http://docs.python.org/2/library/collections.html?highlight=collections#collections.Iterable . Lists, generators, strings and tuples, all of those are iterables.
The normal truth value testing works only on lists, not on just any iterable.
As for the other syntax, this recipe is designed to work mostly on Python 2.x, I hadn't even thought of 3.x.
pavel: by the way I've updated my description and I hope it's better now, check it out.
Thanks!
Hi Alan, your're right, please ignore my first comment