OiO.lk Community platform!

Oio.lk is an excellent forum for developers, providing a wide range of resources, discussions, and support for those in the developer community. Join oio.lk today to connect with like-minded professionals, share insights, and stay updated on the latest trends and technologies in the development field.
  You need to log in or register to access the solved answers to this problem.
  • You have reached the maximum number of guest views allowed
  • Please register below to remove this limitation

itertools.islice iterate over input even when stop is smaller than start

  • Thread starter Thread starter ben42code
  • Start date Start date
B

ben42code

Guest
For a custom container wrapping an iterator, I intended to delegate some of my logic to itertools.islice. One consideration was to avoid unnecessary iterations over the wrapped iterator.

When calling itertools.islice(iterable, start, stop, step) with stop<=start, the result is an empty generator, as expected.

But even though it's not absolutely needed, itertools.islice(iterable, start, stop, step) will always iterate at least start number of times over the iterable.

Test case to repro:

Code:
from unittest.mock import Mock
import itertools

iterableMock = Mock()
iterableMock.__iter__ = Mock(return_value=iterableMock)
iterableMock.__next__ = Mock(side_effect=range(10))

iterable = iterableMock
start = 5
stop = 0
step = None

isliceResult = list(itertools.islice(iterable, start, stop, step))
assert isliceResult == []
assert iterableMock.__next__.call_count == 0  # <= FAILS since call_count == 5

Is this behavior:

  • Expected / by design. We want to skip the elements until start is reached no matter what.
  • Just a side effect of the current implementation that only impacts the performance of some corner cases.
  • A potential improvement that can be addressed without concerns.

Documentation can be a bit misleading/misinterpreted on the expected behavior.

  • elements from the iterable are skipped until start is reached
  • it stops at the specified position

The suggested "equivalent implementation" and the source code clearly iterate until start-1. stop parameter is only considered subsequently.
<p>For a custom container wrapping an iterator, I intended to delegate some of my logic to <code>itertools.islice</code>. One consideration was to avoid unnecessary iterations over the wrapped iterator.</p>
<p>When calling <code>itertools.islice(iterable, start, stop, step)</code> with <code>stop<=start</code>, the result is an empty generator, as expected.</p>
<p>But even though it's not absolutely needed, <code>itertools.islice(iterable, start, stop, step)</code> will always iterate at least <code>start</code> number of times over the iterable.</p>
<p>Test case to repro:</p>
<pre class="lang-py prettyprint-override"><code>from unittest.mock import Mock
import itertools

iterableMock = Mock()
iterableMock.__iter__ = Mock(return_value=iterableMock)
iterableMock.__next__ = Mock(side_effect=range(10))

iterable = iterableMock
start = 5
stop = 0
step = None

isliceResult = list(itertools.islice(iterable, start, stop, step))
assert isliceResult == []
assert iterableMock.__next__.call_count == 0 # <= FAILS since call_count == 5
</code></pre>
<p>Is this behavior:</p>
<ul>
<li>Expected / by design. We want to <em>skip the elements until start is reached</em> no matter what.</li>
<li>Just a side effect of the current implementation that only impacts the performance of some corner cases.</li>
<li>A potential improvement that can be addressed without concerns.</li>
</ul>
<p><a href="https://docs.python.org/3/library/itertools.html#itertools.islice" rel="nofollow noreferrer">Documentation</a> can be a bit misleading/misinterpreted on the expected behavior.</p>
<ul>
<li><em>elements from the iterable are skipped until start is reached</em></li>
<li><em>it stops at the specified position</em></li>
</ul>
<p>The suggested <a href="https://docs.python.org/3/library/itertools.html#itertools.islice" rel="nofollow noreferrer">"equivalent implementation"</a> and the <a href="https://github.com/python/cpython/blob/v3.12.4/Modules/itertoolsmodule.c#L1777" rel="nofollow noreferrer">source code</a> clearly iterate until <code>start-1</code>. <code>stop</code> parameter is only considered subsequently.</p>
 

Latest posts

I
Replies
0
Views
1
impact christian
I
Top