This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: itertools islice consumes items when given negative range
Type: behavior Stage:
Components: Library (Lib) Versions: Python 3.6
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: rhettinger Nosy List: Matthew Malcomson, rhettinger
Priority: Keywords:

Created on 2016-06-24 19:13 by Matthew Malcomson, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Messages (2)
msg269206 - (view) Author: Matthew Malcomson (Matthew Malcomson) Date: 2016-06-24 19:13
While the itertools.islice(iterator, n, n) trick is useful as used in the consume recipe, I find the current behaviour if stop is less than start (e.g. itertools.islice(iterator, 3, 0) ) to be surprising.

It still consumes the first three elements of the iterator, in the same manner as when start and stop are equal.
This is what the documentation implies, but I don't know whether that coincidence is by accident or design.

I would expect an iterator that immediately raises StopIteration but doesn't consume anything, but whether that's what most people would expect or not is another matter.
This would match the python version of islice() in the documentation, though I realise that implementation already diverges from the actual one via Issue 27212 .
msg269454 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2016-06-28 23:20
"Surprising" is in the eye of the beholder.  Having islice() always consume at least "start" number of values seems reasonable enough and it is the documented behavior: "If start is non-zero, then elements from the iterable are skipped until start is reached. ... If stop is None, then iteration continues until the iterator is exhausted, if at all; otherwise, it stops at the specified position."  

That covers a lot of cases including the existing consume() recipe and what happens to the iterator if it supplies fewer than start elements: it=iter('abc'); list(islice(it, 4, 4)); print(list(it)).  Also, to my eyes, the current behavior seems like a natural and smooth transition as the arguments transition towards cross-over:

    >>> from itertools import islice

    >>> it = iter('ABCDEFG'); print(list(islice(it, 2, 4)), list(it))
    ['C', 'D'] ['E', 'F', 'G']
    >>> it = iter('ABCDEFG'); print(list(islice(it, 2, 3)), list(it))
    ['C'] ['D', 'E', 'F', 'G']
    >>> it = iter('ABCDEFG'); print(list(islice(it, 2, 2)), list(it))
    [] ['C', 'D', 'E', 'F', 'G']
    >>> it = iter('ABCDEFG'); print(list(islice(it, 2, 1)), list(it))
    [] ['C', 'D', 'E', 'F', 'G']
    >>> it = iter('ABCDEFG'); print(list(islice(it, 2, 0)), list(it))
    [] ['C', 'D', 'E', 'F', 'G']

    >>> it = iter('ABCDEFG'); print(list(islice(it, 0, 2)), list(it))
    ['A', 'B'] ['C', 'D', 'E', 'F', 'G']
    >>> it = iter('ABCDEFG'); print(list(islice(it, 1, 2)), list(it))
    ['B'] ['C', 'D', 'E', 'F', 'G']
    >>> it = iter('ABCDEFG'); print(list(islice(it, 2, 2)), list(it))
    [] ['C', 'D', 'E', 'F', 'G']
    >>> it = iter('ABCDEFG'); print(list(islice(it, 3, 2)), list(it))
    [] ['D', 'E', 'F', 'G']
    >>> it = iter('ABCDEFG'); print(list(islice(it, 4, 2)), list(it))
    [] ['E', 'F', 'G']

Putting in your suggested optimization to treat start > stop as being fully consumed from the outset would have some big disadvantages.  It would break existing code relying on the current reasonable and documented behavior of always eating at least "start" elements.  And it would incentivize a new and weird idiom for "consume" as islice(it, n, 0).

As far as I can tell, the current behavior hasn't been problematic for anyone in the almost 15 year history of the itertools module, so it is hard to get excited enough about this to want to incur those disadvantages.
History
Date User Action Args
2022-04-11 14:58:33adminsetgithub: 71571
2016-06-28 23:20:13rhettingersetpriority: normal ->
status: open -> closed
resolution: not a bug
messages: + msg269454
2016-06-24 19:15:58serhiy.storchakasetassignee: rhettinger

nosy: + rhettinger
2016-06-24 19:13:32Matthew Malcomsoncreate