lang2
lang2

Reputation: 11966

What's the point of the iter() built-in?

With iter(), I can do this:

>>> listWalker = iter ( [23, 47, 'hike'] )
>>> for x in listWalker: print x,

But I could do this anyway:

>>> listWalker = [23, 47, 'hike']
>>> for x in listWalker: print x,

What value does it add?

Upvotes: 3

Views: 786

Answers (4)

chepner
chepner

Reputation: 531315

In addition to using iter to explicitly get an iterator for an object that implements the __iter__ method, there is the lesser-known two-argument form of iter, which makes an iterator which repeatedly calls a function until it returns a given sentinel value.

 for line in iter(f.readline, 'EOF'):
     print line

The preceding code would call f.read (for, say, an open file handle f) until it reads a line consisting of the string EOF. It's roughly the same as writing

for line in f:
    if line == "EOF":
        break
    print line

Additionally, an iterator may be a distinct object from the object it iterates over. This is true for the list type. That means you can create two iterators, both of which iterate independently over the same object.

itr1 = iter(mylist)
itr2 = iter(mylist)

x = next(itr1)   # First item of mylist
y = next(itr1)   # Second item of my list
z = next(itr2)   # First item of mylist, not the third

File handles, however, act as their own iterator:

>>> f = open('.bashrc')
>>> id(f)
4454569712
>>> id(iter(f))
4454569712

In general, the object returned by iter depends on the __iter__ method implemented by the object's type.

Upvotes: 6

user4815162342
user4815162342

Reputation: 155046

The point of iter is that it allows you to obtain the iterator from an iterable object and use it yourself, either to implement your own variant of the for loop, or to maintain the state of the iteration across multiple loops. A trivial example:

it = iter(['HEADER', 0, 1, 2, 3])  # coming from CSV or such
title = it.next()
for item in it:
    # process item
    ...

A more advanced usage of iter is provided by this grouping idiom:

def in_groups(iterable, n):
    """Yield element from iterables grouped in tuples of size n."""
    it = iter(iterable)
    iters = [it] * n
    return zip(*iters)

Upvotes: 5

Javier
Javier

Reputation: 2776

From the docs:

iter(o[, sentinel])

[...] Without a second argument, o must be a collection object which supports the iteration protocol (the __iter__() method), or it must support the sequence protocol (the __getitem__() method with integer arguments starting at 0). If it does not support either of those protocols, TypeError is raised. [...]

So it constructs an iterator from an object.

As you say, this is done automatically in loops and comprehensions but some times you want to get an iterator and handle it directly. Just keep it in the back of your mind until you need it.

When using the second argument:

If the second argument, sentinel, is given, then o must be a callable object. The iterator created in this case will call o with no arguments for each call to its next() method; if the value returned is equal to sentinel, StopIteration will be raised, otherwise the value will be returned.

This is useful for many things but particularly so for legacy style functions like file.read(bufsize) which has to be called repeatedly until it returns "". That can be converted to an iterator with iter(lambda : file.read(bufsize), ""). Nice and clean!

Upvotes: 0

Maxime Lorant
Maxime Lorant

Reputation: 36161

When you're doing a for loop on a variable, it implicitly call the __iter__ method of the iterable you passed in fact.
You're always using iter() is some way when you're looping over lists, tuples... and every iterable.

I think this extract of byte-code can convince you:

>>> def a():
...     for x in [1,2,3]:
...         print x
...
>>> import dis
>>> dis.dis(a)
  2           0 SETUP_LOOP              28 (to 31)
              3 LOAD_CONST               1 (1)
              6 LOAD_CONST               2 (2)
              9 LOAD_CONST               3 (3)
             12 BUILD_LIST               3
             15 GET_ITER                                 # <--- get iter is important here
        >>   16 FOR_ITER                11 (to 30)
             19 STORE_FAST               0 (x)

  3          22 LOAD_FAST                0 (x)
             25 PRINT_ITEM
             26 PRINT_NEWLINE
             27 JUMP_ABSOLUTE           16
        >>   30 POP_BLOCK
        >>   31 LOAD_CONST               0 (None)
             34 RETURN_VALUE


But, iterables allows you also some other things in Python, such as the use of next() to walk into an iterable, or raising a StopIteration exception. It can be useful if you're dealing with different object types and you want to apply a generic algorithm.

Upvotes: 0

Related Questions