82

I want to use the traditional C-style for loop in Python. I want to loop through characters of a string, but also know what it is, and be able to jump through characters (e.g. i =5 somewhere in the code).

for with range doesn't give me the flexibility of an actual for loop.

4
  • 6
    Any chance you could disclose what you need C-style looping for? There might be a better, more Pythonic way we could suggest. Commented Feb 26, 2012 at 4:10
  • 7
    Python does not have a goto statement. Commented Feb 26, 2012 at 4:11
  • This question has already been discussed and answered elsewhere on Stack Overflow: stackoverflow.com/questions/2740901/… Commented Jul 5, 2013 at 5:07
  • 1
    @Karl: implementing Boyer-Moore algorithm for educational purposes, maybe? There are various text-processing scenarios where you might want to jump forwards. None of which you have much chance of doing correctly until you're further along in Python than this, but you need a goal when you get started ;-) Commented Jul 2, 2020 at 5:11

11 Answers 11

93

There is no simple, precise equivalent of C's for statement in Python. Other answers cover using a Python for statement with a range, and that is absolutely what you should do when possible.

If you want to be able to modify the loop variable in the loop (and have it affect subsequent iterations), you have to use a while loop:

i = 0
while i < 7:
    if someCondition(i):
        i = 5
    i += 1

But in that loop, a continue statement will not have the same effect that a continue statement would have in a C for loop. If you want continue to work the way it does in C, you have to throw in a try/finally statement:

i = 0
while i < 7:
    try:
        if someCondition(i):
            i = 5
        elif otherCondition(i):
            continue
        print 'i = %d' % i
    finally:
        i += 1

As you can see, this is pretty ugly. You should look for a more Pythonic way to write your loop.

UPDATE

This just occurred to me... there is a complicated answer that lets you use a normal Python for loop like a C-style loop, and allows updating the loop variable, by writing a custom iterator. I wouldn't recommend this solution for any real programs, but it's a fun exercise.

Example “C-style” for loop:

for i in forrange(10):
    print(i)
    if i == 3:
        i.update(7)

Output:

0
1
2
3
8
9

The trick is forrange uses a subclass of int that adds an update method. Implementation of forrange:

class forrange:

    def __init__(self, startOrStop, stop=None, step=1):
        if step == 0:
            raise ValueError('forrange step argument must not be zero')
        if not isinstance(startOrStop, int):
            raise TypeError('forrange startOrStop argument must be an int')
        if stop is not None and not isinstance(stop, int):
            raise TypeError('forrange stop argument must be an int')

        if stop is None:
            self.start = 0
            self.stop = startOrStop
            self.step = step
        else:
            self.start = startOrStop
            self.stop = stop
            self.step = step

    def __iter__(self):
        return self.foriterator(self.start, self.stop, self.step)

    class foriterator:

        def __init__(self, start, stop, step):
            self.currentValue = None
            self.nextValue = start
            self.stop = stop
            self.step = step

        def __iter__(self): return self

        def next(self):
            if self.step > 0 and self.nextValue >= self.stop:
                raise StopIteration
            if self.step < 0 and self.nextValue <= self.stop:
                raise StopIteration
            self.currentValue = forrange.forvalue(self.nextValue, self)
            self.nextValue += self.step
            return self.currentValue

    class forvalue(int):
        def __new__(cls, value, iterator):
            value = super(forrange.forvalue, cls).__new__(cls, value)
            value.iterator = iterator
            return value

        def update(self, value):
            if not isinstance(self, int):
                raise TypeError('forvalue.update value must be an int')
            if self == self.iterator.currentValue:
                self.iterator.nextValue = value + self.iterator.step
Sign up to request clarification or add additional context in comments.

5 Comments

I agree that @kev's answer is idiomatic, and it's what I use whenever possible. But the question clearly asked for a C-style for loop, in which you can change the value of the loop variable.
"I wouldn't recommend this solution for any real programs", is it because of performance or readability? Or some other reason?
It's confusing.
it's possible with a simple range operator, what was all this nonsense
Tell me you didn’t understand the question without telling me you didn’t understand the question.
90

In C:

for(int i=0; i<9; i+=2)
{
    dosomething(i);
}

In python3:

for i in range(0, 9, 2):
    dosomething(i)

You just express the same idea in different languages.

5 Comments

Thanks, but I can't modify I in the for like I can in other languages.
1) What do you hope to accomplish by doing so? 2) You certainly can assign to i within the body of the Python loop. It just won't have any effect on the underlying list object created by range.
This correspondence breaks down when you try to translate a more sophisticated looping construct like the following: for(int i=1; i<16; i*=2){...}.
Thanks and this is really good. For someone like me who thinks in C, this helps with implementing the idea in Python quickly
Range just does not work with floats for instance. It's much easier to step from -10.0 to 10.0 by 0.10 increments in C than in Python.
18
for i in range(n):

...is the Python equivalent of the C...

for (i = 0; i < n; i++){

Or well, you can use:

for i in range(a, n, s):

...which is equivalent to...

for (i = a; i < n; i+=s){

2 Comments

What about other kinds of operations in a for loop like division or multiplication? (e.g. for(int I =0; I < x; I*=5)
not in a nested loop
14

I provide the following entirely facetious solution by way of protest. Note that 'break' and 'continue' will not work. Also note that the loop body must not be indented.

class For:
    def __init__(self, **loop_vars):
        self.loop_vars = loop_vars
    def __call__(self, arg):
        if not hasattr(self, 'condition'):
            self.condition = arg
            return self
        if not hasattr(self, 'update'):
            self.update = arg
            return self
        while eval(self.condition, self.loop_vars, self.loop_vars):
            exec arg in self.loop_vars
            exec self.update in self.loop_vars


For(i = 1, j = 1)('i * j < 50')('i += 1; j += 1')('''
print i, j
''')

Comments

10

Since Python 3.8, we have the assignment expression operator or "walrus" operator, :=. Its use is just what it sounds like, turning assignments into expressions, returning the assigned value like assignment always does in C. Since we can put expressions in conditions, this allows us to write a while loop and have continue still update the loop variable like it would in C, since the condition is always checked.

In C:

for (int i = 0; i < 7; ++i) {
    if (i == 3) { // skip 3
        continue;
    }
    printf("i = %d\n", i);
}

In Python:

i = -1
while (i := i+1) < 7:
    if i == 3: # skip 3
        continue
    print(f'i = {i}')

Both output:

i = 0
i = 1
i = 2
i = 4
i = 5
i = 6

Note, using a while loop and updating the loop variable at the end works fine as long you don't need continue. For example, the following code results in an infinite loop:

i = 0
while i < 7:
    if i == 3: # skip 3
        continue 
    print(f'i = {i}')
    i += 1 # will never be reached once i == 3. Infinite loop!

2 Comments

Great solution. This does allow the sort of "adding extra to i to skip ahead" that OP is asking for. Using i = 5 for example.
I learned something new today! :D Thanks for this! :)
5

You can do the following, given an array a:

for i in range(len(a)):
  a[i] = i

That's the closest Python can get to C-style loops.

You can also give the range command more arguments; for example,

for i in range(2, len(a), 3)

will start at i = 2, and increment it by 3 as long as the result is less than len(a).

Comments

3

The Python for loop always has foreach semantics. You can, however, do this:

for i in xrange(10):
    print i

This is very much like a C for loop. xrange (or range, as it was renamed in Python 3) is a constructor for a Python object that iterates through a range of numbers. See the docs for more information.

Comments

3

The top answer here is fundamentally incorrect in any true for-looping situation. And the second answer does address the issue, but over complicates things (a C-loop is possible).

Bottom Line, Up Front (BLUF):

## The code:

i = -1
length = 100
while i < length - 1:
  i += 1
  # ...


## With comments:

# start from -1 to enable continues (adapt as needed)
i = -1 
length = 100
while i < length - 1: # the loop
  # increment @ 1st line to duplicate C loop and allow normal continues  
  i += 1 
  # proceed as if in scope of: for(i=0; i < len(orig_line); i++)

Discussion:

For example, in writing a loop in a process that genuinely deserves a loop (such as across a string or for some algorithm's internal method), it is often desirable to have a loop and slide structure:

for (int i = 0; i < 100; i++){
  char c = my_string[i];
  if (c != '(') continue;
  while (c != ')') {
     // do whatever, collect the content etc.
     i++
     c = my_string[i];
  }
  // do something else here
}

HOWEVER, in python:

for i in range(100):
  c = my_string[i]
  
  if c != '(':
     // do whatever
     continue
  
  while c != ')':
    // collect the content
    i += 1
    c = my_string[i]

  // do something else here

Generates the ith value from the range yield, and therefore does not respect modifications to i from within the loop!

Opinion:

I can't think of any other language consistent with this design choice other than the shell languages using the seq tool. But we are employed to write python to craft applications, not scripts. That makes this design choice annoying. Bear in mind that languages die due to the accumulation of annoying choices.

It also means that python doesn't actually have a for loop; it has iterators and recognizes what we are calling a for loop as a grammatical construct for iterating.

Python is getting fast now as technique and implementation improves. All of us are using it for a variety of problems. Perhaps it is time to give python a real for-loop.

Comments

2

For all the ones going "Why?", here's an example where a C-style loop would be helpful:

remaining_retries = 3
for i in range(num_runs):
  success = do_run()
  if not success and remaining_retries > 0:
    i = i - 1
    remaining_retries = remaning_retries - 1

Comments

2

An idea is to have a generator that yields an object, in which lies the loop variable. That way, you can have both the original generator and the loop accessing the same loop variable. Naturally, this then allows you to update the loop variable.

def c_for(i, cond_f, post_f):
    it = [i]
    while cond_f(it[0]):
        yield it
        it[0] = post_f(it[0])


for it in c_for(0, lambda i: i < 10, lambda i: i + 1):
    i = it[0]
    print(i, end=" ")
    if i == 5:
        it[0] = 7
print()

This prints:

0 1 2 3 4 5 8 9 

The answer by Ethan is nice, but I did not like the fact that the loop variable has to start at one less than the first value. I was thinking of the following, but it looks equally bad:

i_loop = False
while (i := i + 1 if i_loop else 0, i_loop := True)[0] < 7:
    if i == 3:  # skip 3
        continue
    print(i, end=" ")
print()

Comments

0

Perhaps I may give another motivating example: if the size of the list may change during the loop. The token gobble replaces itself and the next two tokens with gulp.

lines = ['a', 'gobble', 'c', 'd', 'e', 'f', 'g']
i = 0
while i < len(lines):
      if lines[i] == 'gobble':
            lines[i:i+3] = ['gulp']
      i += 1
for l in lines: print(l)

This could not easily be written as for l in lines or even for i, l in enumerate(lines). The loop exit condition needs to check the length of the list each time.

Of course, if you had to do more elaborate processing, for example a new token ignore which suppresses the special behaviour of the following token, then you'd be able to implement that easily by changing the value of i.

As others mentioned, you do have to be careful if you use continue, and make sure the increment of i happens in a finally block if so.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.