6

许多 Python 的内置函数(any(),all()sum())都采用可迭代对象,但为什么不len()呢?

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

4

2 回答 2

12

许多迭代是由没有明确定义的 len 的生成器表达式定义的。采取以下永远迭代的方法:

def sequence(i=0):
    while True:
        i+=1
        yield i

基本上,要获得明确定义的长度,您需要预先了解整个对象。将其与sum. 您不需要一次知道整个对象来对其求和——只需一次取一个元素并将其添加到您已经求和的内容中。

小心像这样的习语sum(1 for i in iterable),通常它只会耗尽可迭代的,所以你不能再使用它了。或者,如果涉及大量计算,获取第 i 个元素可能会很慢。可能值得问问自己为什么需要先验知道长度。这可能会让您深入了解要使用哪种类型的数据结构(经常list并且tuple工作得很好)——或者您可以执行您的操作而无需调用len.

于 2012-07-13T01:53:04.987 回答
7

这是一个可迭代的:

def forever():
    while True:
        yield 1

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

len(list(the_iterable))

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

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

num_elements = len(the_iterable)
for element in the_iterable:
    ...

做:

num_elements = 0
for element in the_iterable:
    num_elements += 1
    ...

如果您想要一种高效的方式来查看最终有多少元素被理解,例如:

num_relevant = len(x for x in xrange(100000) if x%14==0)

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

num_relevant = len([x for x in xrange(100000) if x%14==0])

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

num_relevant = sum(1 for _ in (x for x in xrange(100000) if x%14==0))

因此,您可能应该编写自己的函数:

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)

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

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

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


编辑:啊,在那种情况下你会使用exhaustive_len(open("file.txt")),因为你必须一个接一个地处理文件中的所有行以查看有多少行,并且通过调用list.

于 2012-07-13T01:52:48.993 回答