成员资格测试结果与list和csv.reader不同

时间:2014-01-09 17:42:56

标签: python csv

如果我检查列表的成员资格而不是csv.reader对象,我会得到不同的结果。 以下使用unittest模块。

csv.reader测试会员资格

with open("file.tab", 'rb') as f:
    reader = csv.reader(f, delimiter='\t')
    self.assertTrue(['1', '2', '3', '4'] in reader)
    self.assertTrue(['2', '3', '4', '5'] in reader)
    self.assertTrue(['3', '4', '5', '6'] in reader)

列出会员资格测试

with open("file.tab", 'rb') as f:
    reader = csv.reader(f, delimiter='\t')
    reader = [record for record in reader]
    self.assertTrue(['1', '2', '3', '4'] in reader)
    self.assertTrue(['2', '3', '4', '5'] in reader)
    self.assertTrue(['3', '4', '5', '6'] in reader)

我知道file.tab包含我正在测试的三个记录的条目,但第三个断言在使用csv.reader时出现“False is true”,并在使用列表时传递。

csv.reader是一个发电机; docs没有明确说出来,但由于我可以用尽它,我认为这意味着它是一个发电机。我的想法可能是这个原因,但下面的测试只打印出真实的内容:

x = xrange(5)
for m in range(5):
    for n in range(5):
        print m in x
        print n in x

这让我觉得使用生成器测试成员资格没有问题。

为什么第三个断言语句在使用csv.reader时的评估方式与使用列表时不同?

2 个答案:

答案 0 :(得分:5)

那里你运气不好 - xrange实际上并不是一个发电机,而是一种特殊类型的发电机,它表现得懒散,所以可以欺骗你以为它是一个。

>>> x = xrange(10)
>>> 5 in x
True
>>> 5 in x
True

>>> it = iter(range(10))
>>> 5 in it
True
>>> 5 in it
False

所以你的逻辑是正确的:reader实例可能已用尽,但列表不能,这就是为什么成员资格测试可以返回不同的答案,具体取决于内容。请注意,成员资格测试可能会短路,因此如果出现正面结果,则不必耗尽:

>>> it = iter(range(10))
>>> 3 in it
True
>>> next(it)
4

答案 1 :(得分:1)

是的,csv.reader是一个生成器,in在找到值时进行迭代。正如DSM所展示的那样。

在CSV文件中,行的顺序与测试中的顺序不同。如果您更改订单,您的测试将通过:

>>> def fake_reader():
...     yield ['1', '2', '3', '4']
...     yield ['2', '3', '4', '5']
...     yield ['3', '4', '5', '6']

>>> reader = fake_reader()
>>> ['1', '2', '3', '4'] in reader
True
>>> ['2', '3', '4', '5'] in reader
True
>>> ['3', '4', '5', '6'] in reader
True

如果订单不同,它就会失败:

>>> def fake_reader():
...     yield ['1', '2', '3', '4']
...     yield ['3', '4', '5', '6'] # changed order
...     yield ['2', '3', '4', '5']

>>> reader = fake_reader()
>>> ['1', '2', '3', '4'] in reader # reads one row
True
>>> ['2', '3', '4', '5'] in reader # reads two rows!
True
>>> ['3', '4', '5', '6'] in reader # there are no more rows to read
False