1

I have seen the code in heapq.nlargest() of Python standardlib as following:

if n == 1:
    it = iter(iterable)
    sentinel = object()
    if key is None:
        result = max(it, default=sentinel)
    else:
        result = max(it, default=sentinel, key=key)
    return [] if result is sentinel else [result]

It convert iterable to it by iter() first, and then to get maximum value from it by max() function passed argument it.

Why don't just use iterable object? Are there any advantage I have no awareness?

yixuan
  • 375
  • 2
  • 17

2 Answers2

6

In the current code, there is no advantage. The line could be safely removed, just passing iterable into max directly.

I think this is just a remnant of an earlier implementation, which used islice:

# Short-cut for n==1 is to use max() when len(iterable)>0
if n == 1:
    it = iter(iterable)
    head = list(islice(it, 1))
    if not head:
        return []
    if key is None:
        return [max(chain(head, it))]
    return [max(chain(head, it), key=key)]

This is from 18e9512. Taking an explicit iterator was not removed in a later optimization, although it could have been, i.e. 277842e.

For a good example of when it is useful to convert an iterable into a consumable iterator first, take a look at the question Finding subsequence (nonconsecutive)

wim
  • 338,267
  • 99
  • 616
  • 750
3

There is no advantage to it = iter(iterable) in the code shown and that line should be removed. max calls iter() (or the C equivalent) on the first argument making the original call completely redundant.

There are cases where it is useful, such as an iterator that is only partially consumed in several steps. In a wildly contrived example, you may want the first value and then everything after 3. This demonstrates using next to get a value, a for loop to consume more and finally passing to another function/class to consume whatever is left over. Note that next would raise StopIteration if there were no values, but the other two work fine even if the iterator has been exhausted.

iterable = [1,2,3,4,5]
it = iter(iterable)
first = next(it)
for x in it:
    if x == 3:
        break

final = list(it)
print(first, final)
tdelaney
  • 73,364
  • 6
  • 83
  • 116