python -- 可调用迭代器的大小?

14 投票
6 回答
17867 浏览
提问于 2025-04-16 01:55

我正在查看一个文本文件,想用某种方法找到特定的字符串。

re.finditer(pattern,text) 我想知道在什么情况下这个方法会返回空,也就是说它在传入的文本中找不到任何东西。

我知道可调用的迭代器有 next()__iter__ 这两个方法。

我想知道是否可以获取结果的大小,或者如何判断它是否没有找到与我的模式匹配的字符串。

6 个回答

5

不,抱歉,迭代器并不知道集合的长度,它们只知道下一个元素是什么。这使得它们在遍历集合时非常高效。虽然迭代器的速度更快,但它们不支持索引,也就是说,它们不能告诉你集合的长度。

21

这个方案使用的内存更少,因为它不保存中间结果,而其他使用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。

7

编辑 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>
>>> 

撰写回答