Is it possible to implement a Python for range loop without an iterator variable?

PythonLoopsFor LoopRange

Python Problem Overview


Is it possible to do following without the i?

for i in range(some_number):
    # do something

If you just want to do something N amount of times and don't need the iterator.

Python Solutions


Solution 1 - Python

Off the top of my head, no.

I think the best you could do is something like this:

def loop(f,n):
    for i in xrange(n): f()

loop(lambda: <insert expression here>, 5)

But I think you can just live with the extra i variable.

Here is the option to use the _ variable, which in reality, is just another variable.

for _ in range(n):
    do_something()

Note that _ is assigned the last result that returned in an interactive python session:

>>> 1+2
3
>>> _
3

For this reason, I would not use it in this manner. I am unaware of any idiom as mentioned by Ryan. It can mess up your interpreter.

>>> for _ in xrange(10): pass
...
>>> _
9
>>> 1+2
3
>>> _
9

And according to Python grammar, it is an acceptable variable name:

identifier ::= (letter|"_") (letter | digit | "_")*

Solution 2 - Python

You may be looking for

for _ in itertools.repeat(None, times): ...

this is THE fastest way to iterate times times in Python.

Solution 3 - Python

The general idiom for assigning to a value that isn't used is to name it _.

for _ in range(times):
    do_stuff()

Solution 4 - Python

What everyone suggesting you to use _ isn't saying is that _ is frequently used as a shortcut to one of the http://docs.python.org/library/gettext.html">gettext</a> functions, so if you want your software to be available in more than one language then you're best off avoiding using it for other purposes.

import gettext
gettext.bindtextdomain('myapplication', '/path/to/my/language/directory')
gettext.textdomain('myapplication')
_ = gettext.gettext
# ...
print _('This is a translatable string.')

Solution 5 - Python

Here's a random idea that utilizes (abuses?) the data model (Py3 link).

class Counter(object):
    def __init__(self, val):
        self.val = val

    def __nonzero__(self):
        self.val -= 1
        return self.val >= 0
    __bool__ = __nonzero__  # Alias to Py3 name to make code work unchanged on Py2 and Py3

x = Counter(5)
while x:
    # Do something
    pass

I wonder if there is something like this in the standard libraries?

Solution 6 - Python

You can use _11 (or any number or another invalid identifier) to prevent name-colision with gettext. Any time you use underscore + invalid identifier you get a dummy name that can be used in for loop.

Solution 7 - Python

May be answer would depend on what problem you have with using iterator? may be use

i = 100
while i:
    print i
    i-=1

or

def loop(N, doSomething):
    if not N:
        return
    print doSomething(N)
    loop(N-1, doSomething)
    
loop(100, lambda a:a)

but frankly i see no point in using such approaches

Solution 8 - Python

Instead of an unneeded counter, now you have an unneeded list. Best solution is to use a variable that starts with "_", that tells syntax checkers that you are aware you are not using the variable.

x = range(5)
while x:
  x.pop()
  print "Work!"

Solution 9 - Python

I generally agree with solutions given above. Namely with:

  1. Using underscore in for-loop (2 and more lines)
  2. Defining a normal while counter (3 and more lines)
  3. Declaring a custom class with __nonzero__ implementation (many more lines)

If one is to define an object as in #3 I would recommend implementing protocol for with keyword or apply contextlib.

Further I propose yet another solution. It is a 3 liner and is not of supreme elegance, but it uses itertools package and thus might be of an interest.

from itertools import (chain, repeat)

times = chain(repeat(True, 2), repeat(False))
while next(times):
    print 'do stuff!'

In these example 2 is the number of times to iterate the loop. chain is wrapping two repeat iterators, the first being limited but the second is infinite. Remember that these are true iterator objects, hence they do not require infinite memory. Obviously this is much slower then solution #1. Unless written as a part of a function it might require a clean up for times variable.

Solution 10 - Python

We have had some fun with the following, interesting to share so:

class RepeatFunction:
    def __init__(self,n=1): self.n = n
    def __call__(self,Func):
        for i in xrange(self.n):
            Func()
        return Func


#----usage
k = 0

@RepeatFunction(7)                       #decorator for repeating function
def Job():
    global k
    print k
    k += 1

print '---------'
Job()

Results:

0
1
2
3
4
5
6
---------
7

Solution 11 - Python

If do_something is a simple function or can be wrapped in one, a simple map() can do_something range(some_number) times:

# Py2 version - map is eager, so it can be used alone
map(do_something, xrange(some_number))

# Py3 version - map is lazy, so it must be consumed to do the work at all;
# wrapping in list() would be equivalent to Py2, but if you don't use the return
# value, it's wastefully creating a temporary, possibly huge, list of junk.
# collections.deque with maxlen 0 can efficiently run a generator to exhaustion without
# storing any of the results; the itertools consume recipe uses it for that purpose.
from collections import deque

deque(map(do_something, range(some_number)), 0)

If you want to pass arguments to do_something, you may also find the itertools repeatfunc recipe reads well:

To pass the same arguments:

from collections import deque
from itertools import repeat, starmap

args = (..., my args here, ...)

# Same as Py3 map above, you must consume starmap (it's a lazy generator, even on Py2)
deque(starmap(do_something, repeat(args, some_number)), 0)

To pass different arguments:

argses = [(1, 2), (3, 4), ...]

deque(starmap(do_something, argses), 0)

Solution 12 - Python

We can use the while & yield, we can create our own loop function like this. Here you can refer to the official documentation.

def my_loop(start,n,step = 1):
    while start < n:
        yield start
        start += step

for x in my_loop(0,15):
    print(x)

Solution 13 - Python

#Return first n items of the iterable as a list
list(itertools.islice(iterable, n))

Taken from http://docs.python.org/2/library/itertools.html

Solution 14 - Python

If you really want to avoid putting something with a name (either an iteration variable as in the OP, or unwanted list or unwanted generator returning true the wanted amount of time) you could do it if you really wanted:

for type('', (), {}).x in range(somenumber):
    dosomething()

The trick that's used is to create an anonymous class type('', (), {}) which results in a class with empty name, but NB that it is not inserted in the local or global namespace (even if a nonempty name was supplied). Then you use a member of that class as iteration variable which is unreachable since the class it's a member of is unreachable.

Solution 15 - Python

What about:

while range(some_number):
    #do something

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJames McMahonView Question on Stackoverflow
Solution 1 - PythonUnknownView Answer on Stackoverflow
Solution 2 - PythonAlex MartelliView Answer on Stackoverflow
Solution 3 - PythonRyanView Answer on Stackoverflow
Solution 4 - PythonIgnacio Vazquez-AbramsView Answer on Stackoverflow
Solution 5 - PythonsaffsdView Answer on Stackoverflow
Solution 6 - PythonJirkaVView Answer on Stackoverflow
Solution 7 - PythonAnurag UniyalView Answer on Stackoverflow
Solution 8 - PythonRobert JacobsView Answer on Stackoverflow
Solution 9 - PythonYauhen YakimovichView Answer on Stackoverflow
Solution 10 - PythonDeveloperView Answer on Stackoverflow
Solution 11 - PythonmtdView Answer on Stackoverflow
Solution 12 - PythonKushal BhavsarView Answer on Stackoverflow
Solution 13 - PythonestaniView Answer on Stackoverflow
Solution 14 - PythonskykingView Answer on Stackoverflow
Solution 15 - PythonAdam ScottView Answer on Stackoverflow