Understanding input in iter

Question:

I was looking for solutions to take multiline input in python. I found this answer which uses the following code.

sentinel = '' # ends when this string is seen
for line in iter(input, sentinel):
    pass # do things here

I read from the python docs that if iter recieves the second argument then it will call the __next__() of the first argument. But I don’t think input has the __next__() implemented (I am not able to verify this either through the docs or surfing through the source code). Can someone explain how it’s working?

Also, I observed this weird behaviour with the following code.

sentinel = ''
itr = iter(input, sentinel)
print("Hello")
print(set(itr))

Here is the output

[dvsingla Documents]$ python3 temp.py
Hello
lksfjal
falkja
 aldfj

{' aldfj', 'falkja', 'lksfjal'}
[dvsingla Documents]$ 

The prompt starts taking input after printing Hello which is not following line by line interpretation.

Thanks for any help

Asked By: Dhruv

||

Answers:

iter has three forms: two one-arg and a two-arg version. The first one-arg version is the one that you are likely more familiar with.

  1. If object supports __iter__, iter will call that and return the result.

  2. If not, iter will look for __getitem__ (which is assumed to accept integers at that point) and __len__. If both are found in object, iter will instantiate its own internal iterator type that has a __next__ method which increments the index to object.__getitem__ calls until it reaches __len__.

  3. The two-arg form is much less used (and probably less known). It takes two arguments: object is a no-arg callable, and sentinel is a value that will be compared to what object returns to determine the end of iteration. In this case iter returns an instance of an internal class which supports __next__, just like for #2. Each call to __next__ will delegate to object until it returns sentinel. That’s the version that you see being used here.

In all three cases, object itself does not need to implement __next__ directly. The iterator returned by iter does. For case #1, that’s something object produces. For cases #2 and #3, is a wrapper made by iter.

The reason that the printouts happen as they do is that all forms of iter return a lazy iterator, not just the first form. itr will not execute anything until the call to set, which will repeatedly call input through itr.__next__(). This will continue until the user enters an empty line, which will be equal to the chosen sentinel.

Answered By: Mad Physicist
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.