-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
Copy pathLoopVariableCapture.qhelp
60 lines (54 loc) · 1.98 KB
/
LoopVariableCapture.qhelp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Nested functions are a useful feature of Python as it allows a function to access the variables of its enclosing function.
However, the programmer needs to be aware that when an inner function accesses a variable in an outer scope,
it is the variable that is captured, not the value of that variable.
</p>
<p>
Therefore, care must be taken when the captured variable is a loop variable, since it is the loop <em>variable</em> and
<em>not</em> the <em>value</em> of that variable that is captured.
This will mean that by the time that the inner function executes,
the loop variable will have its final value, not the value when the inner function was created.
</p>
</overview>
<recommendation>
<p>
The simplest way to fix this problem is to add a local variable of the same name as the outer variable and initialize that
using the outer variable as a default.
<code>
for var in seq:
...
def inner_func(arg):
...
use(var)
</code>
becomes
<code>
for var in seq:
...
def inner_func(arg, var=var):
...
use(var)
</code>
</p>
</recommendation>
<example>
<p>
In this example, a list of functions is created which should each increment its argument by its index in the list.
However, since <code>i</code> will be 9 when the functions execute, they will each increment their argument by 9.
</p>
<sample src="LoopVariableCapture.py" />
<p>
This can be fixed by adding the default value as shown below. The default value is computed when the function is created, so the desired effect is achieved.
</p>
<sample src="LoopVariableCapture2.py" />
</example>
<references>
<li>The Hitchhiker’s Guide to Python: <a href="http://docs.python-guide.org/en/latest/writing/gotchas/#late-binding-closures">Late Binding Closures</a></li>
<li>Python Language Reference: <a href="https://docs.python.org/reference/executionmodel.html#naming-and-binding">Naming and binding</a></li>
</references>
</qhelp>