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

ABM*_*ABM 1 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)
Run Code Online (Sandbox Code Playgroud)

列出成员资格测试

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)
Run Code Online (Sandbox Code Playgroud)

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

csv.reader是一个生成器; 该文档没有明确说,但因为我可能会耗尽它,我认为这意味着它是一台发电机.我的想法是这可能是原因,但以下测试只打印出真实的内容:

x = xrange(5)
for m in range(5):
    for n in range(5):
        print m in x
        print n in x
Run Code Online (Sandbox Code Playgroud)

这让我觉得测试发电机的会员资格没有问题.

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

DSM*_*DSM 5

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

>>> x = xrange(10)
>>> 5 in x
True
>>> 5 in x
True
Run Code Online (Sandbox Code Playgroud)

>>> it = iter(range(10))
>>> 5 in it
True
>>> 5 in it
False
Run Code Online (Sandbox Code Playgroud)

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

>>> it = iter(range(10))
>>> 3 in it
True
>>> next(it)
4
Run Code Online (Sandbox Code Playgroud)