Modifying global variables in doctests
<p>The doctest documentation has <a href="https://docs.python.org/3.5/library/doctest.html#what-s-the-execution-context" rel="nofollow">a section about execution context</a>.
My reading is that the globals in the module are shallow copied for the tests in each docstring, but are not reset between tests within a docstring.</p>

<p>Based on that description, I would have thought the following doctests would pass:</p>

<pre><code>X = 1


def f():
    """Function F.

    &gt;&gt;&gt; X
    1
    &gt;&gt;&gt; f()
    2
    &gt;&gt;&gt; X
    2
    """
    global X
    X = 2
    return X


def g():
    """Function G.

    &gt;&gt;&gt; g()
    1
    &gt;&gt;&gt; X
    1
    """
    return X
</code></pre>

<p>But instead the following tests pass!</p>

<pre><code>X = 1


def f():
    """Function F.

    &gt;&gt;&gt; X
    1
    &gt;&gt;&gt; f()
    2
    &gt;&gt;&gt; X
    1
    """
    global X
    X = 2
    return X


def g():
    """Function G.

    &gt;&gt;&gt; g()
    2
    &gt;&gt;&gt; X
    1
    """
    return X
</code></pre>

<p>It seems like the globals are shared across tests across docstrings?
But only within function calls?</p>

<p>Why is this the resulting behavior?
Does this have something to do with functions having a dictionary of globals separate from the execution context?</p>

<p>Not exactly.  While it is true that the globals are shallow copied, what you are actually seeing is the scoping of globals (using the keyword <code>global</code>) and how it actually operates at the module level in Python.  You can observe this by putting in a <a href="https://docs.python.org/library/pdb.html#pdb.set_trace" rel="nofollow"><code>pdb.set_trace()</code></a> inside function <code>f</code> right after the assignment (<code>X = 2</code>).</p>

<pre><code>$ python -m doctest foo.py
&gt; /tmp/foo.py(18)f()
-&gt; return X
(Pdb) bt
  /usr/lib/python2.7/runpy.py(162)_run_module_as_main()
-&gt; "__main__", fname, loader, pkg_name)
  /usr/lib/python2.7/runpy.py(72)_run_code()
-&gt; exec code in run_globals
  /usr/lib/python2.7/doctest.py(2817)&lt;module&gt;()
-&gt; sys.exit(_test())
  /usr/lib/python2.7/doctest.py(2808)_test()
-&gt; failures, _ = testmod(m)
  /usr/lib/python2.7/doctest.py(1911)testmod()
-&gt; runner.run(test)
  /usr/lib/python2.7/doctest.py(1454)run()
-&gt; return self.__run(test, compileflags, out)
  /usr/lib/python2.7/doctest.py(1315)__run()
-&gt; compileflags, 1) in test.globs
  &lt;doctest foo.f[1]&gt;(1)&lt;module&gt;()
-&gt; f()
&gt; /tmp/foo.py(18)f()
-&gt; return X
(Pdb) pp X
2
</code></pre>

<p>Yes, the value is indeed <code>2</code> within the scope of <code>f</code>, but let's take a look of its globals.  Let's look at how they compare in the current frame and up a frame.</p>

<pre><code>(Pdb) id(globals())
140653053803048  # remember this number, and we go up a frame
(Pdb) u
&gt; &lt;doctest foo.f[1]&gt;(1)&lt;module&gt;()
-&gt; f()
(Pdb) id(globals())
140653053878632  # the "shallow" clone
(Pdb) X
1
(Pdb) c
</code></pre>

<p>Ah ha, you can see that they are NOT actually the same thing, and that <code>X</code> is indeed <code>1</code> and has not been changed, because the globals there are within the <code>&lt;doctest doc.f&gt;</code> module created by doctest for this reason.  Let's continue.</p>

<pre><code>(Pdb) id(globals())
140653053803048  # hey look, is the SAME number we remember
(Pdb) u
&gt; &lt;doctest foo.g[0]&gt;(1)&lt;module&gt;()
-&gt; g()
(Pdb) id(globals())
140653053872960  # note how this is a different shallow clone
</code></pre>

<p>So what you actually saw is that the globals within the doctest is not the same one as the one on your source (hence <code>g</code> will return <code>2</code> because <code>X</code> was  really was changed in the module here by <code>f</code>, but not in the doctest module shallow copy scope), even though it originally was copied from the module but the changes are not reflected back to the underlying module since this is how the <code>global</code> keyword operates - at the module level, not across modules.</p>

python global-variables doctest