mirror of
https://github.com/github/codeql.git
synced 2025-12-24 20:56:33 +01:00
61 lines
2.0 KiB
XML
61 lines
2.0 KiB
XML
<!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>
|