修改doctests中的全局变量

时间:2016-08-30 23:43:40

标签: python global-variables doctest

doctest文档有a section about execution context。 我的读法是模块中的全局变量是为每个文档字符串中的测试复制的,但不会在文档字符串中的测试之间重置。

基于该描述,我认为以下doctests将通过:

X = 1


def f():
    """Function F.

    >>> X
    1
    >>> f()
    2
    >>> X
    2
    """
    global X
    X = 2
    return X


def g():
    """Function G.

    >>> g()
    1
    >>> X
    1
    """
    return X

但是以下测试通过了!

X = 1


def f():
    """Function F.

    >>> X
    1
    >>> f()
    2
    >>> X
    1
    """
    global X
    X = 2
    return X


def g():
    """Function G.

    >>> g()
    2
    >>> X
    1
    """
    return X

似乎整个文档在跨文档字符串的测试中共享? 但只在函数调用中?

为什么这是由此产生的行为? 这是否与具有与执行上下文分离的全局变量字典的函数有关?

1 个答案:

答案 0 :(得分:0)

不完全是。虽然全局变量是浅层复制的,但您实际看到的是全局变量的范围(使用关键字global)以及它在Python中如何在模块级别实际运行。您可以在分配后立即pdb.set_trace()内部函数fX = 2)来观察此事。

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

是的,2范围内的值确实是f,但让我们来看看它的全局变量。让我们看一下它们在当前帧和帧中的比较方式。

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

啊哈,你可以看到它们实际上并不是同一个东西,X确实是1并且没有被改变,因为那里的全局变量都在<doctest doc.f>内由doctest为此创建的模块。让我们继续。

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

所以你实际看到的是doctest中的全局变量与你的源中的全局变量不同(因此g将返回2,因为X确实被更改了在这里的模块f,但不是在doctest模块浅复制范围内),即使它最初是从模块复制但是更改没有反映回底层模块,因为这是{{1关键字操作 - 在模块级别,而不是跨模块。