python -- 可调用迭代器的大小?
我正在查看一个文本文件,想用某种方法找到特定的字符串。
re.finditer(pattern,text)
我想知道在什么情况下这个方法会返回空,也就是说它在传入的文本中找不到任何东西。
我知道可调用的迭代器有 next()
和 __iter__
这两个方法。
我想知道是否可以获取结果的大小,或者如何判断它是否没有找到与我的模式匹配的字符串。
6 个回答
不,抱歉,迭代器并不知道集合的长度,它们只知道下一个元素是什么。这使得它们在遍历集合时非常高效。虽然迭代器的速度更快,但它们不支持索引,也就是说,它们不能告诉你集合的长度。
这个方案使用的内存更少,因为它不保存中间结果,而其他使用list
的方案则会保存这些结果:
sum(1 for _ in re.finditer(pattern, text))
之前的方案有个缺点,就是如果文本中出现的模式非常频繁,比如模式'[a-z]',它们会消耗很多内存。
测试案例:
pattern = 'a'
text = 10240000 * 'a'
这个使用sum(1 for ...)
的方案大约只需要和文本本身一样多的内存,也就是len(text)
字节。而之前那些使用list
的方案,所需的内存大约是必要内存的58到110倍。对于32位的Python 2.7来说,这大约是580 MB,而对于64位的则是1.1 GB。
编辑 3: @hynekcer 的回答比这个好太多了。
编辑 2: 如果你有一个无限的迭代器,或者一个消耗太多内存(在2010年,1GB的内存仍然是很大的)的迭代器,这个方法就不管用了。
你已经看到了一个不错的答案,但这里有一个代价高昂的技巧,如果你想两全其美,可以试试 :) 这个窍门是我们需要复制这个“蛋糕”,等你吃完后,再把它放回同一个盒子里。记住,当你遍历迭代器时,它通常会变空,或者至少会失去之前返回的值。
>>> def getIterLength(iterator):
temp = list(iterator)
result = len(temp)
iterator = iter(temp)
return result
>>>
>>> f = xrange(20)
>>> f
xrange(20)
>>>
>>> x = getIterLength(f)
>>> x
20
>>> f
xrange(20)
>>>
编辑: 这里有一个更安全的版本,但使用它仍然需要一些自律。这种方式感觉不是很符合Python的风格。如果你能把你想实现的完整相关代码示例发出来,可能会得到更好的解决方案。
>>> def getIterLenAndIter(iterator):
temp = list(iterator)
return len(temp), iter(temp)
>>> f = iter([1,2,3,7,8,9])
>>> f
<listiterator object at 0x02782890>
>>> l, f = getIterLenAndIter(f)
>>>
>>> l
6
>>> f
<listiterator object at 0x02782610>
>>>