【问题标题】:Modifying global variables in doctests修改文档测试中的全局变量
【发布时间】:2016-08-30 23:43:39
【问题描述】:

doctest 文档有a section about execution context。 我的阅读是模块中的全局变量是针对每个文档字符串中的测试进行浅拷贝的,但不会在文档字符串中的测试之间重置。

根据该描述,我认为以下 doctest 会通过:

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

似乎全局变量是跨文档字符串在测试之间共享的? 但只在函数调用中?

为什么会出现这种行为? 这是否与具有与执行上下文分开的全局字典的函数有关?

【问题讨论】:

    标签: python global-variables doctest


    【解决方案1】:

    不完全是。虽然全局变量确实是浅拷贝的,但您实际看到的是全局变量的作用域(使用关键字global)以及它在 Python 中在模块级别的实际操作方式。您可以通过在赋值 (X = 2) 之后立即在函数 f 中放入 pdb.set_trace() 来观察这一点。

    $ 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
    

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

    (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 为此创建的 &lt;doctest doc.f&gt; 模块中原因。让我们继续吧。

    (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 确实在模块中被 @ 更改了987654337@,但不在 doctest 模块浅拷贝范围内),即使它最初是从模块复制的,但更改不会反映回底层模块,因为这是 global 关键字的操作方式 - 在模块级别,不跨模块。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-01
      • 2013-01-14
      相关资源
      最近更新 更多