Leschge
Leschge

Reputation: 164

Change stepsize of for loop while in loop

is there a method where I can change the stepsize of a for loop, while I am in the loop?

E.g. this doesn't seem to work:

stepsize = 1.
for i in np.arange(0.,10.,stepsize):
   print i
   if i > 5:
      print "change"
      stepsize = 0.5

Output:

0.0
1.0
2.0
3.0
4.0
5.0
6.0
change
7.0
change
8.0
change
9.0
change

Upvotes: 0

Views: 3493

Answers (2)

Anis R.
Anis R.

Reputation: 6912

The problem

The issue is that when you declare your for loop as such:

for i in np.arange(0.,10.,stepsize):

The range object gets evaluated before the loop starts executing, and then never gets modified. As an analogy, consider this integer example:

a = 0
b = a + 1 #b is evaluated using the *current* value of a, which is 0
a = 1
print(b) # 0 + 1 = 1

The same applies for this for loop declaration, as it is equivalent to:

myRange = np.arange(0.,10.,stepsize)
for i in myRange:
    #...
    stepsize = 0.5 #will NOT affect the already initialized myRange variable!!

A simple solution

Therefore, the easiest solution is, in my opinion, to simply use a while loop, and increment your counter according to your if condition:

i = 1.
while i < 10:
    print i
    if i > 5:
        print "change"
        i += 0.5 #condition met, increment by 0.5 instead of 1
    else:
        i += 1 #otherwise, increment by 1

Upvotes: 3

Kelly Bundy
Kelly Bundy

Reputation: 27629

Not with np.arange, as that gives you a fully materialized array:

>>> r = np.arange(0., 1000000., 1)
>>> type(r)
<class 'numpy.ndarray'>
>>> r.__sizeof__()
8000048

So after it is created, it's simply too late. Also, it has no access to your stepsize variable, so couldn't notice that you changed it.

Compare to range, which is a lightway object that calculates values on the fly:

>>> r = range(0, 1000000, 1)
>>> type(r)
<class 'range'>
>>> r.__sizeof__()
24

(Note I'm using Python 3... you should really join us. Not just because in Python 2 the equivalent has the ugly name xrange.)

Now... that range object does have a step attribute:

>>> dir(r)
['__bool__', '__class__', ..., 'count', 'index', 'start', 'step', 'stop']

But it won't let us change it:

>>> r.step = 2
Traceback (most recent call last):
  File "<pyshell#46>", line 1, in <module>
    r.step = 2
AttributeError: readonly attribute

You could use your own range class supporting such a state change, though:

class Range:
    def __init__(self, start, stop, step):
        self.current = start
        self.stop = stop
        self.step = step
    def __iter__(self):
        while self.current < self.stop:
            yield self.current
            self.current += self.step

for i in (r := Range(0, 10, 1)):
   print(i)
   if i > 5:
      print("change")
      r.step = 0.5

Output:

0
1
2
3
4
5
6
change
6.5
change
7.0
change
7.5
change
8.0
change
8.5
change
9.0
change
9.5
change

Upvotes: 1

Related Questions