Reputation: 9531
Consider these two variants of the same loop structure:
x = find_number_of_iterations()
for n in range(x):
# do something in loop
and:
for n in range(find_number_of_iterations()):
# do something
Will the second loop evaluate the method find_number_of_iterations
in every subsequent loop run, or will the method find_number_of_iterations
be evaluated only once even in the second variant?
Upvotes: 0
Views: 71
Reputation: 52008
I suspect that your mentor's confusion is traceable to the fact that the semantics of Python's for loop is so much different than in other languages.
In a language like C a for loop is more or less syntactic sugar for a while loop:
for(i = 0; i < n; i++)
{
//do stuff
}
is equivalent to:
i = 0;
while(i < n)
{
//do stuff
i++
}
In Python it is different. Its for loops are iterator-based. The iterator object is initialized just once and then consumed in subsequent iterations. The following snippets show that Python's for loop is not (easily) translatable into a while loop, and also shows that with a while loop your mentor's concern is valid:
>>> def find_number_of_iterations():
print("called")
return 3
>>> for i in range(find_number_of_iterations()): print(i)
called
0
1
2
>>> i = 0
>>> while i < find_number_of_iterations():
print(i)
i += 1
called
0
called
1
called
2
called
Upvotes: 1
Reputation: 122116
Either way, the function only gets called once. You can demonstrate this as follows:
>>> def test_func():
"""Function to count calls and return integers."""
test_func.called += 1
return 3
# first version
>>> test_func.called = 0
>>> x = test_func()
>>> for _ in range(x):
print 'loop'
loop
loop
loop
>>> test_func.called
1
# second version
>>> test_func.called = 0
>>>
>>> for _ in range(test_func()):
print 'loop'
loop
loop
loop
>>> test_func.called
1
The function is called once, and the result of calling that function is passed to range
(then the result of calling range
is iterated over); the two versions are logically equivalent.
Upvotes: 1
Reputation: 15167
The function is called once. Logically, were it to be called on every iteration then the loop range could change causing all kinds of havoc. This is easily tested:
def find_iterations():
print "find_iterations called"
return 5
for n in range(find_iterations()):
print n
Results in:
$ python test.py
find_iterations called
0
1
2
3
4
Upvotes: 1