6

I know iterator is iterable, but only 1 pass.

For example, many functions in itertools take iterable as parameter, e.g islice. Can I always pass in iterator if I see the api says iterable?

As @delnan pointed out:

Although every iterator is an iterable, some people (outside the core team) say "iterable" when they mean "something that can be iterated several times with with the same results". Some code in the wild claims to work on iterables but actually doesn't work with iterators.

That is exact my concern. Is there a name for those iterable which support multipass? Like IEnumerable in C#?

If I am to build a function which claims to support iterable, is it best practice to actually support iterator as well?

colinfang
  • 20,909
  • 19
  • 90
  • 173
  • 3
    Although every iterator is an iterable, some people (outside the core team) say "iterable" when they mean "something that can be iterated several times with with the same results". Some code in the wild claims to work on iterables but actually doesn't work with iterators and other one-shot iterables (e.g. files). –  Oct 28 '13 at 20:04
  • @delnan That is exact my concern. Is there a name for those `iterable` which support multipass? Like `IEnumerable` in C#. – colinfang Oct 28 '13 at 20:08
  • 3
    I believe the word `iterable` has two distinct meanings: one is technical, and the other is general. The confusion arise from mixing the two. In *general* terms an `iterable` is an object that can be used in a `for` loop. Period. In the technical sense an `iterable` is an object that defines the `__iter__` method. `iterable`s, in the technical sense, do *not* give any guarantee on multiple iterations. If you want to do multiple passes you want a *sequence*, or you can convert the `iterable` into a sequence to perform the multiple iterations, or you can use `itertools.tee`. – Bakuriu Oct 28 '13 at 20:30
  • http://stackoverflow.com/questions/9884132/understanding-pythons-iterator-iterable-and-iteration-protocols-what-exact – georg Oct 28 '13 at 20:40
  • 2
    I suppose if you needed to test for an iterable that is not an iterator, you could do `iter(iterable) is not iterable`, since iterators are required to return themselves from `__iter__`. – Blckknght Oct 28 '13 at 22:04
  • @colinfang files are iterators, and every iterator is an iterable. See http://docs.python.org/3/glossary.html#term-iterable –  Oct 29 '13 at 11:36

3 Answers3

6

Yes, the functions in itertools are designed for use with iterators. The reason why the function signatures say iterable is because they also work on lists, tuples, and other iterables which are not iterators.


A sequence is an iterable which supports efficient element access using integer indices via the __getitem__() special method and defines a len() method that returns the length of the sequence.

This definition is slightly different than the set of all iterables which are not iterators. (You could define a (crippled) custom class which has a __getitem__, method but not a __len__. It would be an iterable which is not an iterator -- but neither would it be a sequence.)

However sequences is pretty close to what you are looking for, since all sequences are iterables which can be iterated over multiple times.

Examples of sequence types built into Python include str, unicode, list, tuple, bytearray, buffer and xrange.


Here are some definitions culled from the glossary:

container
    Has a __contains__ method

generator
    A function which returns an iterator.

iterable
    An object with an __iter__() or __getitem__() method. Examples of
    iterables include all sequence types (such as list, str, and
    tuple) and some non-sequence types like dict and file. When an
    iterable object is passed as an argument to the builtin function
    iter(), it returns an iterator for the object. This iterator is
    good for one pass over the set of values.

iterator
    An iterable which has a next() method.  Iterators are required to
    have an __iter__() method that returns the iterator object
    itself. An iterator is good for one pass over the set of values.

sequence
    An iterable which supports efficient element access using integer
    indices via the __getitem__() special method and defines a len()
    method that returns the length of the sequence. Note that dict
    also supports __getitem__() and __len__(), but is considered a
    mapping rather than a sequence because the lookups use arbitrary
    immutable keys rather than integers.  sequences are orderable
    iterables.

    deque is a sequence, but collections.Sequence does not recognize
    deque as a sequence.
    >>> isinstance(collections.deque(), collections.Sequence)
    False
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
3

Yes, because every iterator is also an iterable.

An object is iterable if it defines the __iter__() method. Every iterator has this method, it returns the iterator itself.

flornquake
  • 3,156
  • 1
  • 21
  • 32
2

You should look at the abstract base classes defined in the collections module. For your purposes, Container or Sized might be the most useful, as they require __contains__ and __len__ respectively, which in turn require a well defined set of values that could be iterated over repeatedly.

Blckknght
  • 100,903
  • 11
  • 120
  • 169