为什么len()不支持迭代器?

iru*_*var 6 python iterable

许多Python的内置函数(any(),all(),sum()命名一些)采取iterables但为什么len()不呢?

人们总是可以使用它sum(1 for i in iterable)作为等价物,但为什么它首先len()不采用迭代?

mgi*_*son 12

许多迭代是由生成器表达式定义的,这些表达式没有明确定义的len.采取永远迭代的以下内容:

def sequence(i=0):
    while True:
        i+=1
        yield i
Run Code Online (Sandbox Code Playgroud)

基本上,要有一个明确定义的长度,您需要预先知道整个对象.对比像这样的功能sum.您不需要一次知道整个对象来总结它 - 只需一次取一个元素并将其添加到您已经总结的内容中.

要小心这些习语sum(1 for i in iterable),通常它会耗尽迭代,所以你不能再使用它了.或者,如果涉及大量计算,则获取第i个元素可能会很慢.可能值得问自己为什么你需要知道a-priori的长度.这可能给你一些洞察到使用(经常是什么类型的数据结构listtuple工作得很好) -或者你可以,而无需调用执行您的操作len.


Cla*_*diu 7

这是一个可迭代的:

def forever():
    while True:
        yield 1
Run Code Online (Sandbox Code Playgroud)

然而,它没有长度.如果你想找到有限迭代的长度,唯一的方法就是这样做,通过定义迭代是什么(你可以重复调用以获得下一个元素,直到你到达终点)是完全扩展迭代,例如:

len(list(the_iterable))
Run Code Online (Sandbox Code Playgroud)

正如mgilson指出的那样,您可能想问自己 - 为什么要知道特定迭代的长度?请随意发表评论,我将添加一个具体的例子.

如果要跟踪已处理的元素数量,而不是执行以下操作:

num_elements = len(the_iterable)
for element in the_iterable:
    ...
Run Code Online (Sandbox Code Playgroud)

做:

num_elements = 0
for element in the_iterable:
    num_elements += 1
    ...
Run Code Online (Sandbox Code Playgroud)

如果你想要一种记忆效率高的方式来查看最终有多少元素在理解中,例如:

num_relevant = len(x for x in xrange(100000) if x%14==0)
Run Code Online (Sandbox Code Playgroud)

这样做效率不高(你不需要整个列表):

num_relevant = len([x for x in xrange(100000) if x%14==0])
Run Code Online (Sandbox Code Playgroud)

sum 可能是最方便的方式,但它看起来很奇怪,并不是很清楚你在做什么:

num_relevant = sum(1 for _ in (x for x in xrange(100000) if x%14==0))
Run Code Online (Sandbox Code Playgroud)

所以,你应该编写自己的函数:

def exhaustive_len(iterable):
    length = 0
    for _ in iterable: length += 1
    return length

exhaustive_len(x for x in xrange(100000) if x%14==0)
Run Code Online (Sandbox Code Playgroud)

长名称是为了帮助提醒您它确实消耗了迭代,例如,这不会像您想象的那样工作:

def yield_numbers():
    yield 1; yield 2; yield 3; yield 5; yield 7

the_nums = yield_numbers()
total_nums = exhaustive_len(the_nums)
for num in the_nums:
    print num
Run Code Online (Sandbox Code Playgroud)

因为exhaustive_len已经消耗了所有元素.


编辑:啊,在这种情况下你会使用exhaustive_len(open("file.txt")),因为你必须逐个处理文件中的所有行,看看有多少行,并通过调用将整个文件存储在内存中将是浪费list.