如果我检查列表的成员资格而不是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时的评估方式与使用列表时不同?
答案 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