# "for i in range()" to do an infinite loop with a counter

**URL:** <https://discuss.python.org/t/for-i-in-range-to-do-an-infinite-loop-with-a-counter/18108>\
**Category:** Ideas\
**Created:** [August 10, 2022, 11:19am UTC](https://discuss.python.org/t/for-i-in-range-to-do-an-infinite-loop-with-a-counter/18108 "2022-08-10T11:19:10Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![josephernest](https://avatars.discourse-cdn.com/v4/letter/j/76d3ee/32.png) [@josephernest](https://discuss.python.org/u/josephernest)\
**Post date:** [August 10, 2022, 11:19am UTC](https://discuss.python.org/t/for-i-in-range-to-do-an-infinite-loop-with-a-counter/18108/1 "2022-08-10T11:19:10Z")

</div>

Hi,  
Usually in Python we can avoid the `i = 0` … `i += 1` paradigm that we use in other languages when we need to count things, thanks to `enumerate(...)`, `for i in range(100)`, etc.  
Along the years I have nearly always found a more “pythonic” replacement for code containing `i = 0` … `i += 1`.

There is an exception with this code: an infinite loop with a counter:

```auto
i = 0
while True:
    ...
    if breaking_condition:
        break
    i += 1

```

Proposal: could we accept that `range()` without any parameter gives an infinite iteration?

Example:

```auto
for i in range(): # infinite loop
    print(i)
    if breaking_condition:
        break

```

Basically `range()` without parameter would have the same behaviour than:

```auto
import itertools
for i in itertools.count():
    if breaking_condition:
        break

```

Have you considered making this available directly, without any import, with `range()`?

* * *

Linked topic: [Looping from 1 to infinity in Python](https://stackoverflow.com/questions/9884213/looping-from-1-to-infinity-in-python).

---

<div class="post-metadata">

**Author:** ![ericvsmith](https://avatars.discourse-cdn.com/v4/letter/e/34f0e0/32.png) [@ericvsmith](https://discuss.python.org/u/ericvsmith)\
**Post date:** [August 10, 2022, 11:26am UTC](https://discuss.python.org/t/for-i-in-range-to-do-an-infinite-loop-with-a-counter/18108/2 "2022-08-10T11:26:24Z")

</div>

Since the `itertools.count()` version works fine, I don’t think we’d add another way of doing the same thing.

---

<div class="post-metadata">

**Author:** ![josephernest](https://avatars.discourse-cdn.com/v4/letter/j/76d3ee/32.png) [@josephernest](https://discuss.python.org/u/josephernest)\
**Post date:** [August 10, 2022, 11:48am UTC](https://discuss.python.org/t/for-i-in-range-to-do-an-infinite-loop-with-a-counter/18108/3 "2022-08-10T11:48:22Z")

</div>

Maybe, but this would be nice generalization of  
`for i in range(100)` (count from 0 to 99) to `for i in range()` (count from 0 to infinity).

This benefit comes for free, since `range` currently can’t be called with 0 argument.

Also, it seeems rather logical and nice syntax:

```
range(stop)
range(start, stop)
range(start, stop, step)
range() # we don't have a "stop" argument so it never stops

```

---

<div class="post-metadata">

**Author:** ![storchaka](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/storchaka/32/217_2.png) [@storchaka](https://discuss.python.org/u/storchaka)\
**Post date:** [August 10, 2022, 12:12pm UTC](https://discuss.python.org/t/for-i-in-range-to-do-an-infinite-loop-with-a-counter/18108/4 "2022-08-10T12:12:14Z")

</div>

And since we don’t have a “start” argument, it never starts, right? 😜

Jokes aside, you would need to define `len(range())`, `reversed(range())`, `range()[-1]`, `range()[::-1]`, `x in range()`. And you would see that `range()` is a very special object, different from ordinary range object in many ways. So why call it `range()` and not `count()`? I am sure that this option was already discussed when the `itertools` module was added, and there were reasons of adding `itertools.count()`.

---

<div class="post-metadata">

**Author:** ![ericvsmith](https://avatars.discourse-cdn.com/v4/letter/e/34f0e0/32.png) [@ericvsmith](https://discuss.python.org/u/ericvsmith)\
**Post date:** [August 10, 2022, 1:19pm UTC](https://discuss.python.org/t/for-i-in-range-to-do-an-infinite-loop-with-a-counter/18108/5 "2022-08-10T13:19:31Z")

</div>

> [@josephernest](#):
>
> `range() # we don't have a "stop" argument so it never stops`

Not having a `start` value would be a non-starter (pun not intended). It would have fewer features than `itertools.count()`. I can see maybe doing something that has more features, but not the same or fewer.

---

<div class="post-metadata">

**Author:** ![josephernest](https://avatars.discourse-cdn.com/v4/letter/j/76d3ee/32.png) [@josephernest](https://discuss.python.org/u/josephernest)\
**Post date:** [August 10, 2022, 1:47pm UTC](https://discuss.python.org/t/for-i-in-range-to-do-an-infinite-loop-with-a-counter/18108/6 "2022-08-10T13:47:53Z")

</div>

> [@ericvsmith](#):
>
> Not having a `start` value would be a non-starter (pun not intended). It would have fewer features than `itertools.count()`.

We could have a `start` value and no `stop` value:

```auto
for i in range(start=17): # no stop argument
   print("We'll never stop!")

```

---

<div class="post-metadata">

**Author:** ![ericvsmith](https://avatars.discourse-cdn.com/v4/letter/e/34f0e0/32.png) [@ericvsmith](https://discuss.python.org/u/ericvsmith)\
**Post date:** [August 10, 2022, 1:49pm UTC](https://discuss.python.org/t/for-i-in-range-to-do-an-infinite-loop-with-a-counter/18108/7 "2022-08-10T13:49:30Z")

</div>

I think `range()` is already complicated enough.

---

<div class="post-metadata">

**Author:** ![josephernest](https://avatars.discourse-cdn.com/v4/letter/j/76d3ee/32.png) [@josephernest](https://discuss.python.org/u/josephernest)\
**Post date:** [August 10, 2022, 2:01pm UTC](https://discuss.python.org/t/for-i-in-range-to-do-an-infinite-loop-with-a-counter/18108/8 "2022-08-10T14:01:36Z")

</div>

Probably.

It was just an idea because I often see people doing `i = 0; while True: ... i += 1` in code, and there seemed to be an improvement “for free” with a range with no `stop`: `range()` or `range(start=100)`.  
But anyway, not a big deal.

Have a nice day everyone!

---

<div class="post-metadata">

**Author:** ![ericvsmith](https://avatars.discourse-cdn.com/v4/letter/e/34f0e0/32.png) [@ericvsmith](https://discuss.python.org/u/ericvsmith)\
**Post date:** [August 10, 2022, 3:00pm UTC](https://discuss.python.org/t/for-i-in-range-to-do-an-infinite-loop-with-a-counter/18108/9 "2022-08-10T15:00:35Z")

</div>

Thanks for starting this thread. It just so happens that yesterday I wrote a `i = 0; while True: ... i += 1` loop, and today I changed it to a `for i in itertools.count()` loop. Definitely an improvement, and one I wouldn’t have made without this thread.

---

<div class="post-metadata">

**Author:** ![josephernest](https://avatars.discourse-cdn.com/v4/letter/j/76d3ee/32.png) [@josephernest](https://discuss.python.org/u/josephernest)\
**Post date:** [August 10, 2022, 3:51pm UTC](https://discuss.python.org/t/for-i-in-range-to-do-an-infinite-loop-with-a-counter/18108/10 "2022-08-10T15:51:45Z")

</div>

Haha, happy for this 🙂  
This is a good sign that we shouldn’t have to `import` anything to do this (in the same way we don’t import anything to `enumerate`), and that `for i in range()` would be perfect, but I promiss I stop now haha! (we can close this thread).

---

<div class="post-metadata">

**Author:** ![Dutcho](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/dutcho/32/7074_2.png) [@Dutcho](https://discuss.python.org/u/Dutcho)\
**Post date:** [August 10, 2022, 9:32pm UTC](https://discuss.python.org/t/for-i-in-range-to-do-an-infinite-loop-with-a-counter/18108/11 "2022-08-10T21:32:41Z")

</div>

If you _really_ don’t want to `import itertools`, you could approximate ‘forever’ by [‘Googol’](https://en.wikipedia.org/wiki/Googol)

```auto
for i in range(10**100):
    print(i)
    if i > 3:
        break

```

Actual ‘forever’ can be attained by the longer and more complex:

```auto
for i, _ in enumerate(iter(lambda: 'hell', 'freezes over')):
    print(i)
    if i > 3:
        break

```

Both offer the option of a `start` value, and the first one with `range` also facilitates `step` (if you want to reach googol faster).

---

<div class="post-metadata">

**Author:** ![ncoghlan](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/ncoghlan/32/14266_2.png) [@ncoghlan](https://discuss.python.org/u/ncoghlan)\
**Post date:** [August 17, 2022, 12:34am UTC](https://discuss.python.org/t/for-i-in-range-to-do-an-infinite-loop-with-a-counter/18108/13 "2022-08-17T00:34:37Z")

</div>

> [@storchaka](#):
>
> Jokes aside, you would need to define `len(range())`, `reversed(range())`, `range()[-1]`, `range()[::-1]`, `x in range()`. And you would see that `range()` is a very special object, different from ordinary range object in many ways.

Serhiy’s comment here is the key conceptual reason unbounded ranges aren’t allowed: they’re defined as memory efficient computed sequences rather than consumable iterators, so they’re expected to have a lower and upper bound, even though those limits might be large.

That said, there are already some range operations that throw an exception if the sequence length doesn’t fit in 64 bits, so it isn’t unthinkable to have a special case for “stop=None”. However, unlike the “computed sequence that wouldn’t fit in a 64 bit address space” case, the unbounded sequence case would either slow down multiple operations with extra checks for None, or else we’d have to play constructor games to return a different object type for the special case (and such games are inevitably confusing to maintain).

By contrast, “from itertools import count” is simple to understand conceptually and straightforward to maintain.

---

<div class="post-metadata">

**Author:** ![PlaceReporter99](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/placereporter99/32/13637_2.png) [@PlaceReporter99](https://discuss.python.org/u/PlaceReporter99)\
**Post date:** [July 23, 2023, 5:54pm UTC](https://discuss.python.org/t/for-i-in-range-to-do-an-infinite-loop-with-a-counter/18108/14 "2023-07-23T17:54:02Z")

</div>

for `len(range())` and `range()[-1]` just return `float('inf')`.

---

<div class="post-metadata">

**Author:** ![Zeturic](https://avatars.discourse-cdn.com/v4/letter/z/ecb155/32.png) [@Zeturic](https://discuss.python.org/u/Zeturic)\
**Post date:** [July 23, 2023, 8:26pm UTC](https://discuss.python.org/t/for-i-in-range-to-do-an-infinite-loop-with-a-counter/18108/15 "2023-07-23T20:26:46Z")

</div>

That would require changes to `len`, which currently doesn’t allow float values. For example:

```py
>>> class Foo:
... def __len__ (self):
... return float('inf')
... 
>>> len(Foo())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'float' object cannot be interpreted as an integer

```

My understanding is essentially that `len` does some sanity checks on the result of ` __len__ `.

Sure, it /could/ be changed so that floating-point (or maybe just infinite) lengths are acceptable, but considering the amount of code that assumes that `len` will return an integer, that seems a like a non-starter to me.

As far as the `range()[-1]`, maybe that would be acceptable (though it has a similar problem in that every element in a `range` is supposed to be an integer), but that’s hardly the only issue. As mentioned, what about `reversed(range())`? Or, even more simply, how about `range()[-2]`? Should /every/ negative index just return `float('inf')`?

Having an object that represents a range of integers without an upper bound that still implements parts of the sequence protocol (unlike `itertools.count` which is really just an iterator) might be useful in some situations, but I think that it should be its own class, rather than complicating `range` to support it.

---

<div class="post-metadata">

**Author:** ![davidism](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/davidism/32/3295_2.png) [@davidism](https://discuss.python.org/u/davidism)\
**Post date:** [July 23, 2023, 8:37pm UTC](https://discuss.python.org/t/for-i-in-range-to-do-an-infinite-loop-with-a-counter/18108/16 "2023-07-23T20:37:10Z")

</div>



---

<div class="post-metadata">

**Author:** ![davidism](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/davidism/32/3295_2.png) [@davidism](https://discuss.python.org/u/davidism)\
**Post date:** [July 23, 2023, 8:37pm UTC](https://discuss.python.org/t/for-i-in-range-to-do-an-infinite-loop-with-a-counter/18108/17 "2023-07-23T20:37:48Z")

</div>

This was already answered definitively 11 months ago, no need to resurrect it now.
