例如,Python中的文件是可迭代的 - 它们遍历文件中的行.我想计算行数.
一个快速的方法是这样做:
lines = len(list(open(fname)))
但是,这会将整个文件加载到内存中(一次).这相当违背了迭代器的目的(它只需要将当前行保留在内存中).
这不起作用:
lines = len(line for line in open(fname))
因为发电机没有长度.
有没有办法做到这一点,没有定义计数功能?
def count(i): c = 0 for el in i: c += 1 return c
编辑:澄清,我明白整个文件必须阅读!我只是不想在内存中一次性=).
没有遍历迭代并计算迭代次数,没有.这就是使它成为可迭代而不是列表的原因.这甚至不是特定于python的问题.查看经典的链表数据结构.查找长度是O(n)操作,涉及迭代整个列表以查找元素的数量.
正如上面提到的那样,你可以将你的功能减少到:
def count_iterable(i): return sum(1 for e in i)
当然,如果您要定义自己的可迭代对象,则可以始终实现__len__
自己并在某处保留元素数.
如果你需要一个行数,你可以做到这一点,我不知道有任何更好的方法:
line_count = sum(1 for line in open("yourfile.txt"))
我已经使用了这个重新定义了一段时间了:
def len(thingy): try: return thingy.__len__() except AttributeError: return sum(1 for item in iter(thingy))
该cardinality
包提供了一个有效的count()
函数和一些相关的函数来计算和检查任何iterable的大小:http://cardinality.readthedocs.org/
import cardinality it = some_iterable(...) print(cardinality.count(it))
在内部,它使用enumerate()
并将collections.deque()
所有实际的循环和计数逻辑移动到C级别,从而for
在Python中循环得到相当大的加速.
绝对不是,原因很简单,因为不能保证迭代是有限的.
考虑这个完全合法的生成函数:
def forever(): while True: yield "I will run forever"
尝试计算此功能的长度len([x for x in forever()])
显然不起作用.
正如您所指出的,迭代器/生成器的大部分用途是能够处理大型数据集而无需将其全部加载到内存中.您不能立即获得长度的事实应被视为权衡.