许多Python的内置函数(any()
,all()
,sum()
来命名一些)采用迭代,但为什么len()
没有?
总是可以使用sum(1 for i in iterable)
作为等价物,但为什么len()
不会首先采用迭代?
答案 0 :(得分:10)
许多迭代是由生成器表达式定义的,这些表达式没有明确定义的len。采取永远迭代的以下内容:
def sequence(i=0):
while True:
i+=1
yield i
基本上,要有一个明确定义的长度,您需要预先知道整个对象。将其与sum
之类的函数进行对比。您不需要立即知道整个对象来总结它 - 只需一次取一个元素并将其添加到您已经总结的内容中。
要小心像sum(1 for i in iterable)
这样的习语,通常它会耗尽迭代,所以你不能再使用它了。或者,如果涉及大量计算,则获取第i个元素可能会很慢。可能值得问自己为什么你需要知道a-priori的长度。这可能会让您深入了解要使用的数据结构类型(经常list
和tuple
工作正常) - 或者您可以在不需要调用{{1}的情况下执行操作}。
答案 1 :(得分:6)
这是一个可迭代的:
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
。