Reputation: 27684
Consider the following code:
def my_fun(an_iterable):
for val in an_iterable:
do_work(val)
if some_cond(val):
do_some_other_work(an_iterable)
break
if the an_iterable
is a list
/tuple
, do_some_other_work
will get the whole list again. But if the an_iterable
was a iterator
or a generator
, it will only receive rest of the items in the list. How do I differentiate between two cases? I want do_some_other_work
to receive rest of the items only.
Upvotes: 2
Views: 124
Reputation: 3493
Consider the following snippet:
import types
def which(obj):
if isinstance(obj, types.GeneratorType):
print 'Generator'
elif hasattr(obj, 'next') and (iter(obj) == obj):
print 'Iterator'
elif hasattr(obj, '__iter__'):
print 'Iterable'
else:
print 'Object'
def my_gen(length):
for i in xrange(length):
yield i
# Reports 'Generator'
which(my_gen(10))
# Reports 'Iterable'
which(iter(xrange(10)))
# Reports 'Object'
which([i for i in xrange(10)])
with open('foo.txt', 'w+') as fout:
for _ in xrange(10):
fout.write('hello\n')
# Reports 'Iterable'
with open('foo.txt') as fin:
which(fin)
This identifies them as 'Generator', 'Iterable' and then 'Object'
Upvotes: -1
Reputation: 281330
There's no general way to tell whether you can iterate over an object repeatedly. File-like objects, in particular, are likely to screw up checks. Fortunately, you don't need to check this. If you just want to make sure do_some_other_work
only gets the rest of the items, you can explicitly request an iterator:
def my_fun(iterable):
iterable = iter(iterable)
# Do whatever.
Upvotes: 3