2

Eclipse 平台,Python 3.3。

我创建了下面的代码来演示使用全局变量和 python unittest 时的问题。我想知道为什么第二个单元测试(直接重复第一个)会导致

NameError: global name '_fred' is not defined

尝试注释掉第二个测试,一切都会通过。
(注意:我在示例之后添加了真实代码试图实现的内容的简短摘要,希望它在那里不会那么突兀,因为它与问题并不真正相关)

''' Global Problem
'''
import unittest

_fred = None

def start():
    global _fred
    if _fred is None:
        _fred = 39
    _fred += 3

def stop():
    global _fred
    if _fred is not None:
        del _fred

class Test(unittest.TestCase):
    def setUp(self):
        start()

    def tearDown(self):
        stop()

    def test_running_first_time(self):
        assert(_fred == 42)

    def test_running_second_time(self):
        assert(_fred == 42)

if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testName']
    unittest.main()

在实际代码中,_fred 是引用从 Thread 派生的类的实例的变量(请参阅我在那里所做的)并在 start 方法中分配。
_fred = MyThreadClass()
同步队列还有第二个全局变量。
这些方法启动和停止控制专用线程上的处理队列项。'stop' 在允许添加项目的同时停止处理。
Thread API 只允许启动一次调用。所以要重新开始处理,我需要一个新的 Thread 实例。因此使用

if _fred is None:

del _fred

猜我的主要语言没有奖品

4

3 回答 3

4

del _fred不设置_fredNone或类似的东西。它删除了 name _fred。完全地。对于一个全球来说,就好像它从未存在过一样。对于一个本地人来说,就好像它从未被分配到一样。要将变量设置为None,请执行以下明显操作:

_fred = None
于 2013-05-09T20:47:00.813 回答
2

问题是del _fred。由于您告诉解释器_fred是全局的,_fred因此从全局字典中删除,并且未设置为None. 当你告诉一个函数某些东西是全局的,它会记住,所以当它对该变量名执行操作时,它会全局执行。 global _fredinstart无论如何都不会影响_fred即使_fred未定义的值。这只是由口译员决定的。

于 2013-05-09T20:55:58.643 回答
2

当你这样做时:

def stop():
    global _fred
    if _fred is not None:
        del _fred

您实际上正在访问此模块全局变量字典,并且当 fred 不是 None 时,您正在从模块中删除变量 fred(它不再存在)。单元测试为每个测试方法调用setUp和tearDown,第一个方法的tearDown将从模块变量dict中删除_fred,这将导致第二个setUp失败。

可能这就是你想要做的:

if _fred is not None:
    _fred = None

另一方面,我更喜欢将 start 和 stop 放到一个新类中,并使 _fred 成为此类的全局实例:

class Fred:
    def __init__(self):
        self.state = None

    def start(self):
        if self.state is None:
            self.state = 39
        self.state += 3

    def stop(self):
        if self.state is not None:
            self.state = None

_fred = Fred()

class Test(unittest.TestCase):
    def setUp(self):
        _fred.start()

    def tearDown(self):
        _fred.stop()

    def test_running_first_time(self):
        self.assertEqual(_fred.state, 42)

    def test_running_second_time(self):
        self.assertEqual(_fred.state, 42)
于 2013-05-09T20:56:15.097 回答