# Proposal: Add a \`limit\` parameter to \`enumerate()\`

**URL:** <https://discuss.python.org/t/proposal-add-a-limit-parameter-to-enumerate/108342>\
**Category:** Ideas\
**Created:** [July 31, 2026, 4:50am UTC](https://discuss.python.org/t/proposal-add-a-limit-parameter-to-enumerate/108342 "2026-07-31T04:50:28Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![PythonSJL](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pythonsjl/32/23510_2.png) [@PythonSJL](https://discuss.python.org/u/PythonSJL)\
**Post date:** [July 31, 2026, 4:50am UTC](https://discuss.python.org/t/proposal-add-a-limit-parameter-to-enumerate/108342/1 "2026-07-31T04:50:28Z")

</div>

**I propose adding an optional `limit` parameter to the built-in `enumerate()` function to restrict the number of iterations.**

Limiting iteration is a common task, but current solutions are verbose:

```python
# Current approach: requires import and nesting
from itertools import islice

for i, item in islice(enumerate(data), 5):
    ...

```

Alternatives have downsides: slicing creates copies, and `zip(range(n), data)` ignores the `start` parameter.

Update the signature to: `enumerate(iterable, start=0, limit=None)`

_ **Examples:** _

```python
# Stop after 10 items
for i, line in enumerate(file, limit=10):
    print(i, line)
# Works with start
for i, item in enumerate(data, start=1, limit=3):
    print(i, item)

```

It makes a common pattern more readable and removes the need for `itertools.islice` in simple loops.

_ **Thoughts?** _

---

<div class="post-metadata">

**Author:** ![Rosuav](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/rosuav/32/3429_2.png) [@Rosuav](https://discuss.python.org/u/Rosuav)\
**Post date:** [July 31, 2026, 5:08am UTC](https://discuss.python.org/t/proposal-add-a-limit-parameter-to-enumerate/108342/2 "2026-07-31T05:08:52Z")

</div>

> [@PythonSJL](#):
>
> Alternatives have downsides: slicing creates copies, and `zip(range(n), data)` ignores the `start` parameter.

You could `zip(range(start, start+n), data)` perhaps?

---

<div class="post-metadata">

**Author:** ![OutSquareCapital](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/outsquarecapital/32/35076_2.png) [@OutSquareCapital](https://discuss.python.org/u/OutSquareCapital)\
**Post date:** [July 31, 2026, 6:25am UTC](https://discuss.python.org/t/proposal-add-a-limit-parameter-to-enumerate/108342/3 "2026-07-31T06:25:03Z")

</div>

No thanks. Enumerate is for enumerating, not limiting anything regarding the length of the iteration.

If anything, we should add itertools with clearer intent for take, skip, step\_by, nth, sllice, which are all things that islice can do but are verbose to do.

But a parameter on an unrelated iterator? At that point just add everuthing as parameters to `map` (or worse, find a way to add even more new special syntax to comprehensions)

---

<div class="post-metadata">

**Author:** ![PythonSJL](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pythonsjl/32/23510_2.png) [@PythonSJL](https://discuss.python.org/u/PythonSJL)\
**Post date:** [July 31, 2026, 9:03am UTC](https://discuss.python.org/t/proposal-add-a-limit-parameter-to-enumerate/108342/4 "2026-07-31T09:03:40Z")

</div>

# But I think enumerate(data, s, n) is Superior. Below are my test results just now:

## Test Code

```python
from dis import dis
from itertools import islice
from sys import version
print("Version:", version)
print("Note: n = e - s")
xxx = ("zip(range(s, e), data)",
       "enumerate(data[:n], s)",
       "islice(enumerate(data, s), n)",
       "enumerate(data, s, n) # Hypothetical syntax")
for i, x in enumerate(xxx, 1):
    print("=" * 48)
    print("#", i, ".", x)
    print("-" * 48)
    dis(x)

```

## Bytecode Output

```python
Version: 3.14.2 (tags/v3.14.2:df79316, Dec 5 2025, 17:18:21) [MSC v.1944 64 bit (AMD64)]
Note: n = e - s
================================================
# 1 . zip(range(s, e), data)
------------------------------------------------
  0 RESUME 0
  1 LOAD_NAME 0 (zip)
              PUSH_NULL
              LOAD_NAME 1 (range)
              PUSH_NULL
              LOAD_NAME 2 (s)
              LOAD_NAME 3 (e)
              CALL 2
              LOAD_NAME 4 (data)
              CALL 2
              RETURN_VALUE
================================================
# 2 . enumerate(data[:n], s)
------------------------------------------------
  0 RESUME 0
  1 LOAD_NAME 0 (enumerate)
              PUSH_NULL
              LOAD_NAME 1 (data)
              LOAD_CONST 0 (None)
              LOAD_NAME 2 (n)
              BINARY_SLICE
              LOAD_NAME 3 (s)
              CALL 2
              RETURN_VALUE
================================================
# 3 . islice(enumerate(data, s), n)
------------------------------------------------
  0 RESUME 0
  1 LOAD_NAME 0 (islice)
              PUSH_NULL
              LOAD_NAME 1 (enumerate)
              PUSH_NULL
              LOAD_NAME 2 (data)
              LOAD_NAME 3 (s)
              CALL 2
              LOAD_NAME 4 (n)
              CALL 2
              RETURN_VALUE
================================================
# 4 . enumerate(data, s, n) # Hypothetical syntax
------------------------------------------------
  0 RESUME 0
  1 LOAD_NAME 0 (enumerate)
              PUSH_NULL
              LOAD_NAME 1 (data)
              LOAD_NAME 2 (s)
              LOAD_NAME 3 (n)
              CALL 3
              RETURN_VALUE

```

* * *

## Key Findings

Method 1, `zip(range(s, e), data)`, requires two function calls and involves no slicing or imports. Method 2, `enumerate(data[:n], s)`, uses one function call but introduces `BINARY_SLICE`, creating memory overhead. Method 3, `islice(enumerate(data, s), n)`, involves two function calls and requires an import. The hypothetical Method 4, `enumerate(data, s, n)`, achieves the objective with a single function call, zero slicing, no imports, and the fewest instructions

## Why Method 4 is Better

Minimal function calls: Methods 1 and 3 use nested calls (2 CALL instructions), whereas Method 4 uses just one. This reduces stack frame creation and execution time

Zero slice overhead: Unlike Method 2, which utilizes `BINARY_SLICE` to copy data, Method 4 avoids memory allocation and data duplication, making it suitable for infinite iterators

No import dependency: Method 3 requires `itertools.islice`, while Method 4 uses the built-in function directly

Cleanest bytecode: Method 4 produces the shortest instruction sequence, simply loading arguments and executing a single call

## _ **I hope you can accept my proposal. Thank you** _

---

<div class="post-metadata">

**Author:** ![PythonSJL](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pythonsjl/32/23510_2.png) [@PythonSJL](https://discuss.python.org/u/PythonSJL)\
**Post date:** [July 31, 2026, 9:05am UTC](https://discuss.python.org/t/proposal-add-a-limit-parameter-to-enumerate/108342/5 "2026-07-31T09:05:28Z")

</div>

Yes, although it’s possible, it may not be very good. I think it should be like my new reply 🙂

---

<div class="post-metadata">

**Author:** ![PythonSJL](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pythonsjl/32/23510_2.png) [@PythonSJL](https://discuss.python.org/u/PythonSJL)\
**Post date:** [July 31, 2026, 9:08am UTC](https://discuss.python.org/t/proposal-add-a-limit-parameter-to-enumerate/108342/6 "2026-07-31T09:08:35Z")

</div>

I’ve addressed this in the comment above, please take a look 🙂

---

<div class="post-metadata">

**Author:** ![PythonSJL](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pythonsjl/32/23510_2.png) [@PythonSJL](https://discuss.python.org/u/PythonSJL)\
**Post date:** [July 31, 2026, 9:22am UTC](https://discuss.python.org/t/proposal-add-a-limit-parameter-to-enumerate/108342/7 "2026-07-31T09:22:53Z")

</div>

Of course, changing ‘limit’ to ‘end’ is also possible

---

<div class="post-metadata">

**Author:** ![OutSquareCapital](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/outsquarecapital/32/35076_2.png) [@OutSquareCapital](https://discuss.python.org/u/OutSquareCapital)\
**Post date:** [July 31, 2026, 9:30am UTC](https://discuss.python.org/t/proposal-add-a-limit-parameter-to-enumerate/108342/8 "2026-07-31T09:30:00Z")

</div>

Yep, just read it. I see your point about performance, both for raw execution or import time. They are always valid concerns, but not enough for me to agree with you.

First of all, unless you do that in a nested loop, the function call overhead will be dwarfed by the actual iteration time.

Furthermore, in a general sense, I’m strongly convinced that if you choose to use python, you made the conscious trade-off of prioritizing code clarity and dev speed versus raw speed for every LOC.

Sure you can use polars or numpy for “large” work, but as a whole, your python program will be very slow anyways compared to any compiled language.

And since clarity of code != conciseness of code, I do think that prioritizing said clarity over micro optimisations like this is very often a preferable choice.

Bit of a rant on iterators below, feel free to skip.

I have a strong view on iterators: they should all do a single job, with the least possible amount of parameters. I really like Rust approach with clearly named methods for every behavior. fold and reduce, sort and sort\_by, for example, without “hidden” parameters that completely transform the behavior of the function. So I’m won’t be the easiest one to convince unfortunately. I even do think , for example, that the map approach with multiple iterables is confusing and should have been separated in a new object.

Since python doesn’t have fluent syntax as the standard (e.g `range(10).iter().map().enumerate().take(4).collect(list)`, and instead prioritized comprehensions and imperative for loops, iterators already feel kind of a black box: you are encouraged to inline your logic in a list comprehension, but at the same time to use provided builtins like zip or enumerate that are, at the core, a completely dofferent way of writing iterations. Thus, the more and more we add additional parameters, the more and more we encourage a way of writing iterations were maybe most of the logic is imperative, or functional, which is readed in a completely different way

---

<div class="post-metadata">

**Author:** ![encukou](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/encukou/32/2461_2.png) [@encukou](https://discuss.python.org/u/encukou)\
**Post date:** [July 31, 2026, 9:55am UTC](https://discuss.python.org/t/proposal-add-a-limit-parameter-to-enumerate/108342/9 "2026-07-31T09:55:18Z")

</div>

For simple loops I tend to use an imperative style:

```python
for i, item in enumerate(data):
    if i > 10:
        break
    print(i, item)

```

---

<div class="post-metadata">

**Author:** ![Rosuav](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/rosuav/32/3429_2.png) [@Rosuav](https://discuss.python.org/u/Rosuav)\
**Post date:** [July 31, 2026, 10:04am UTC](https://discuss.python.org/t/proposal-add-a-limit-parameter-to-enumerate/108342/10 "2026-07-31T10:04:44Z")

</div>

> [@PythonSJL](#):
>
> Minimal function calls: Methods 1 and 3 use nested calls (2 CALL instructions), whereas Method 4 uses just one. This reduces stack frame creation and execution time
> 
> Zero slice overhead: Unlike Method 2, which utilizes `BINARY_SLICE` to copy data, Method 4 avoids memory allocation and data duplication, making it suitable for infinite iterators
> 
> No import dependency: Method 3 requires `itertools.islice`, while Method 4 uses the built-in function directly
> 
> Cleanest bytecode: Method 4 produces the shortest instruction sequence, simply loading arguments and executing a single call

Overheads are only relevant when they make a material difference _in context_. Otherwise, you’re playing around with loose nanoseconds while ignoring microseconds. Clean bytecode doesn’t matter much - what your proposal does is move the functionality into the enumerate call, so you don’t see it. (For an extreme example of clean bytecode, look up the HQ9+ language, which has VERY clean bytecode for a VERY specific set of operations. It’s also completely useless for doing actual work.)

Everything is a tradeoff. Having complicated builtins might help your specific case, but it means everyone has to pay the price for them. Instead, _simple_ tools can be built into larger patterns in much more reasonable ways.

---

<div class="post-metadata">

**Author:** ![dg-pb](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/dg-pb/32/16248_2.png) [@dg-pb](https://discuss.python.org/u/dg-pb)\
**Post date:** [July 31, 2026, 1:13pm UTC](https://discuss.python.org/t/proposal-add-a-limit-parameter-to-enumerate/108342/11 "2026-07-31T13:13:29Z")

</div>

> [@PythonSJL](#):
>
> Key Findings

I think runtime would be more useful.

`islice` will not be far off - it doesn’t have `start` - no wasted work.

And `range` will likely be just as fast.

---

<div class="post-metadata">

**Author:** ![duncathan](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/duncathan/32/25521_2.png) [@duncathan](https://discuss.python.org/u/duncathan)\
**Post date:** [July 31, 2026, 2:21pm UTC](https://discuss.python.org/t/proposal-add-a-limit-parameter-to-enumerate/108342/12 "2026-07-31T14:21:12Z")

</div>

I can’t say I’ve ever found myself needing to enumerate with a limit like this. Is it really that common of a pattern?

---

<div class="post-metadata">

**Author:** ![tjreedy](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tjreedy/32/137_2.png) [@tjreedy](https://discuss.python.org/u/tjreedy)\
**Post date:** [July 31, 2026, 2:54pm UTC](https://discuss.python.org/t/proposal-add-a-limit-parameter-to-enumerate/108342/13 "2026-07-31T14:54:41Z")

</div>

-1. Stopping iteration early is not specific to enumerate. Orthogonal generic solutions are better.

islice: Python intentionally does not have thousands of builtins, so as to avoid imports. Composition is fundamental to programming.

if stop\_condition: break: fine if stop condition needs to be dynamically calculated

---

<div class="post-metadata">

**Author:** ![jb2170](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jb2170/32/24298_2.png) [@jb2170](https://discuss.python.org/u/jb2170)\
**Post date:** [July 31, 2026, 9:38pm UTC](https://discuss.python.org/t/proposal-add-a-limit-parameter-to-enumerate/108342/14 "2026-07-31T21:38:55Z")

</div>

Just this week I was thinking about “I wish `enumerate` had a ‘step’ argument, like `range` does”, so that I could change:

```diff
class WordsToBytes(codecs.IncrementalEncoder):
    def encode(self, input: tuple[int], final = False):
        ret_array = bytearray(2 * len(input))

- for idx, word in (
- (2 * i, w)
- for (i, w) in enumerate(input)
- ):
+ for idx, word in enumerate(input, step = 2):
            ret_array[idx + 0] = (word >> 8) & FULL_BYTE_MASK
            ret_array[idx + 1] = (word >> 0) & FULL_BYTE_MASK
            # Tiny bit wasteful, but demonstrates the pattern

        ret = bytes(ret_array)

        return ret

    def feed_eof(self) -> None:
        # button_that_does_nothing.jpg
        self.encode(tuple(), final = True)

```

Seems related / an okay idea, but it was rejected ~20 years ago: [issue892804](https://bugs.python.org/issue892804).

The point being if `limit` were added (which I’m -1 on, and it seems unlikely), could it be a keyword-_only_ argument? Thanks.

---

<div class="post-metadata">

**Author:** ![nedbat](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/nedbat/32/8744_2.png) [@nedbat](https://discuss.python.org/u/nedbat)\
**Post date:** [July 31, 2026, 10:25pm UTC](https://discuss.python.org/t/proposal-add-a-limit-parameter-to-enumerate/108342/15 "2026-07-31T22:25:37Z")

</div>

> [@jb2170](#):
>
> `for idx, word in enumerate(input, step = 2):`

You can use:

```python
for idx, word in zip(itertools.count(step=2), input):

```

The iterator tools in Python are really good at providing a little bit each, and being combinable in powerful ways.

---

<div class="post-metadata">

**Author:** ![hprodh](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hprodh/32/22529_2.png) [@hprodh](https://discuss.python.org/u/hprodh)\
**Post date:** [August 1, 2026, 10:35am UTC](https://discuss.python.org/t/proposal-add-a-limit-parameter-to-enumerate/108342/16 "2026-08-01T10:35:07Z")

</div>

The slice subscript might be a syntax of choice for iterators, similarly as for the lists.  
But for example, `enumerate(items)[0:10:2]` would create a different type than `enumerate`…  
Also consuming `my_iterator[0:10:2]` would basically consume the 10 first elements of `my_iterator` while yielding 5 of them…  
This might yield caveats and confusion.

---

<div class="post-metadata">

**Author:** ![jsbueno](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jsbueno/32/1210_2.png) [@jsbueno](https://discuss.python.org/u/jsbueno)\
**Post date:** [August 1, 2026, 4:09pm UTC](https://discuss.python.org/t/proposal-add-a-limit-parameter-to-enumerate/108342/17 "2026-08-01T16:09:47Z")

</div>

really, I believe this is some confusign semantics here.

If I want to iterate over a subset of the data, I have to throw something to subset the data - quite often, a slice - if it is interactive, islice will do.

THEN…after that, if I want indexes to that data, I will wrap my subset iterable in enumerate.  
Why do the “thing to give me an index of the item” should control 'how many items I get out of this"??

---

<div class="post-metadata">

**Author:** ![Lucas\_Malor](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/lucas_malor/32/24845_2.png) [@Lucas\_Malor](https://discuss.python.org/u/Lucas_Malor)\
**Post date:** [August 14, 2026, 9:50pm UTC](https://discuss.python.org/t/proposal-add-a-limit-parameter-to-enumerate/108342/18 "2026-08-14T21:50:54Z")

</div>

> [@jb2170](#):
>
> “I wish `enumerate` had a ‘step’ argument, like `range` does”

Is there a large use on existing code? I usually search on sourcegraph. The same applies to the proposal.
