2016-08-30 4 views
2

Die Doctest-Dokumentation hat a section about execution context. Meine Lesung ist, dass die Globals in dem Modul flach für die Tests in jedem Docstring kopiert werden, aber nicht zwischen Tests innerhalb eines Docstring zurückgesetzt werden.Ändern von globalen Variablen in Dokumententests

Auf der Grundlage dieser Beschreibung würde ich gedacht haben folgende Doctests passieren würde:

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 

Aber stattdessen gehen die folgenden Tests!

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 

Es scheint, als ob die Globals über Tests hinweg in Docstrings geteilt werden? Aber nur innerhalb Funktionsaufrufe?

Warum ist dies das resultierende Verhalten? Hat das etwas mit Funktionen zu tun, die ein globales Wörterbuch enthalten, das vom Ausführungskontext getrennt ist?

Antwort

0

Nicht genau. Obwohl es stimmt, dass die Globals flach kopiert werden, sehen Sie tatsächlich das Scoping von Globals (mit dem Schlüsselwort global) und wie es tatsächlich auf der Modulebene in Python funktioniert. Sie können dies beobachten, indem Sie direkt nach der Zuweisung eine pdb.set_trace() Innenfunktion f einfügen (X = 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 

Ja, das ist der Wert in der Tat 2 im Rahmen von f, aber lassen Sie sich einen Blick seines Globals nehmen. Schauen wir uns an, wie sie im aktuellen Frame und in einem Frame verglichen werden.

(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 

Ah ha, können Sie sehen, dass sie nicht wirklich die gleiche Sache sind, und dass X ist in der Tat 1 und nicht verändert wurde, weil die Globals dort im <doctest doc.f> Modul erstellt von doctest aus diesem Grunde ist. Lass uns weitermachen.

(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 

Also, was Sie sahen tatsächlich ist, dass die Globals im doctest ist nicht das gleiche wie die auf Ihrer Quelle (daher g kehrt 2 weil X wirklich war, wurde durch f im Modul hier geändert, aber nicht im Doktormodul shallow copy scope), obwohl es ursprünglich aus dem Modul kopiert wurde, aber die Änderungen nicht auf das zugrunde liegende Modul zurückreflektiert werden, da das Schlüsselwort global auf der Modulebene, nicht über Module hinweg funktioniert.

Verwandte Themen