【问题标题】:nose test + class iterator = strange behavior鼻子测试 + 类迭代器 = 奇怪的行为
【发布时间】:2012-08-05 16:10:46
【问题描述】:

我正在创建行为类似于 list() 的类,但您可以向其中添加字符串,这些字符串将被单词上的空格分隔,这些单词将被添加到类实例中。与减法相同:减法从类实例中删除单词(如果有的话)。

我在鼻子测试中遇到了奇怪的行为:当我只是改变断言的顺序时,行为会发生变化。

这里是测试:

from nose.tools import *

def test_isub_str(self):
    u = params()

    u += "1 2 3 4"
    u -= "2 3"

    ok_("1" in u, u)
    ok_("2" not in u, u)
    ok_("3" not in u, u)
    ok_("4" in u, u)

此测试失败,输出如下:

Traceback (most recent call last):
  File "tests.py", line 71, in test_isub_str
    ok_("4" in u, u)
    assert expr, msg
AssertionError: 1 4

奇怪,“u”被转储为“1 4”,但在断言测试期间“u”中没有找到“4”。当我将断言的顺序更改为以下时,最有趣的事情发生了:

ok_("1" in u, u)
ok_("4" in u, u)
ok_("2" not in u, u)
ok_("3" not in u, u)

然后测试顺利通过,这是正确的预期行为。看起来“not in”语句改变了“in”语句的行为。我很惊讶。

最后,这是我的课:

class params():
    def __init__(self):
        self.index = 0 # iterator index
        self.values = [] # list of stored values

    def __iadd__(self, addvalues):
        if isinstance(addvalues, str):
            addvalues = addvalues.split(" ")
        # add all values to this instance if they are list() or params()
        # and not exist in current instance
        if isinstance(addvalues, params) or isinstance(addvalues, list):
            for value in addvalues:
                if isinstance(value, str) and value not in self.values:
                    self.values.append(value)
                else:
                    raise TypeError
            return self
        else:
            raise TypeError

    def __isub__(self, subvalues):
        if isinstance(subvalues, str):
            subvalues = subvalues.split(" ")
        # substract all values from this instance if they are list() or params()
        # and existing in current instance
        if isinstance(subvalues, params) or isinstance(subvalues, list):
            for value in subvalues:
                if isinstance(value, str) and value in self.values:
                    self.values.remove(value)
                else:
                    raise TypeError
            return self
        else:
            raise TypeError

    def __iter__(self):
        return self

    def next(self):
        if self.index >= len(self.values):
            raise StopIteration
        else:
            self.index += 1
            return self.values[self.index - 1]

    def __str__(self):
        return " ".join(self.values)

所以问题是:为什么会发生这种奇怪的行为?我错过了迭代器功能中的一些东西?还是这个鼻子测试错误?

【问题讨论】:

    标签: python unit-testing list iterator nose


    【解决方案1】:

    不,这不是鼻子测试错误,我认为当你这样做时

    ok_("1" in u, u)
    

    u.index 为 1,当你这样做时:

    ok_("2" not in u, u)
    ok_("3" not in u, u)
    

    u.index 是 2。当你这样做时

    ok_("4" in u, u)
    

    u.index 仍为 2,并且您的“下一个”方法引发 StopIteration,因为 2 >= len(self.values)。

    在你的第二种情况下,你这样做时 u.index 仍然是 1:

    ok_("4" in u, u)
    

    【讨论】:

    • 谢谢!这是一个原因!我根据this one等几个不同的示例编写了迭代器方法,所有这些示例都简单地返回了self。这是在每个 __iter__() 调用上重置索引/迭代器的好习惯吗?
    • 我认为在这种情况下最好删除方法next(实际上你的迭代器中没有任何状态)并将__iter__更改为类似这样的东西:iter(self.values)。
    • 再次感谢。我按照你的建议做了,__iter__() 现在真的很简单。
    猜你喜欢
    • 2016-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-21
    相关资源
    最近更新 更多