Python 用迭代器理解len函数
在阅读文档时,我注意到内置函数Python 用迭代器理解len函数,python,python-3.x,Python,Python 3.x,在阅读文档时,我注意到内置函数len不支持所有的iterables,只支持序列和映射(以及集合)。在读这篇文章之前,我一直认为len函数使用迭代协议来计算对象的长度,所以读到这篇文章我真的很惊讶 我阅读了已经发布的问题(和),但我仍然感到困惑,我仍然没有得到不允许len处理所有iterables的真正原因 这是一个更具概念性/逻辑性的原因吗?我的意思是当我问一个对象的长度时,我问的是一个属性(它有多少个元素),一个作为生成器的对象没有的属性,因为它们里面没有元素,生成元素 此外,生成器对象可以生
len
不支持所有的iterables,只支持序列和映射(以及集合)。在读这篇文章之前,我一直认为len
函数使用迭代协议来计算对象的长度,所以读到这篇文章我真的很惊讶
我阅读了已经发布的问题(和),但我仍然感到困惑,我仍然没有得到不允许len
处理所有iterables的真正原因
这是一个更具概念性/逻辑性的原因吗?我的意思是当我问一个对象的长度时,我问的是一个属性(它有多少个元素),一个作为生成器的对象没有的属性,因为它们里面没有元素,生成元素
此外,生成器对象可以生成无限元素,这些元素具有未定义的长度,这是列表、元组、dict等其他对象无法实现的
那么我是对的,还是有更多的见解/我没有考虑的东西?最大的原因是它降低了类型安全性 你写了多少个程序,你实际上需要消耗一个iterable来知道它有多少元素,然后扔掉其他的东西 一、 在用Python编写代码的好几年中,我从来都不需要它。这是正常程序中的非感官操作。迭代器可能没有长度(例如,无限迭代器或期望通过
send()
输入的生成器),因此请求它没有多大意义。len(迭代器)
产生错误的事实意味着您可以在代码中找到bug。您可以看到,在程序的某个部分中,您在错误的事情上调用了len
,或者您的函数实际上需要一个序列,而不是您所期望的迭代器
删除这些错误将创建一类新的bug,其中人们调用len
,错误地使用迭代器,或者像使用序列一样使用迭代器而没有意识到
如果您确实需要知道迭代器的长度,那么len(list(iterator))
有什么问题?额外的6个字符?编写适合迭代器的自己的版本很简单,但是,正如我所说的,99%的情况下,这仅仅意味着代码中存在错误,因为这样的操作没有多大意义
第二个原因是,通过该更改,您违反了len
的两个良好属性,这两个属性当前适用于所有(已知)容器:
- 众所周知,在Python中实现的所有容器(所有内置的、标准的库、
&numpy
和所有其他大型第三方库都在动态大小和静态大小的容器上实现这一点)上都很便宜。因此,当你看到scipy
时,你知道len(某物)
调用很便宜。让它和迭代器一起工作意味着,由于计算长度,所有程序可能突然变得效率低下 还请注意,您可以在每个容器上实现O(1)len
。预先计算长度的成本通常可以忽略不计,并且通常值得支付。 唯一的例外是,如果您实现了不可变的容器,这些容器的内部表示的一部分与其他实例共享(以节省内存)。但是,我不知道有哪种实现可以做到这一点,而且大多数情况下,您可以实现比O(n)时间更好的效果 总而言之:目前每个人都在O(1)中实现\uuu len\uu
,并且很容易继续这样做。因此,对\uu____
的调用应该是O(1)。即使它不是标准的一部分。Python开发人员有意在文档中避免使用C/C++风格的法律术语,并信任用户。在这种情况下,如果您的len
不是O(1),那么您应该记录它\uuuu len\uuuu
- 众所周知,它没有破坏性。
的任何合理实现都不会改变其参数。因此您可以确定
,或者len(x)==len(x)
即使文档中没有定义此属性,但是每个人都期望它,而且目前没有人违反它n=len(x);len(列表(x))==n
另一个次要原因。如果
len
使用迭代器,我肯定有些人会开始滥用它的副作用(取代已经丑陋的map
或列表理解)。突然,人们可以编写如下代码:
len(print(something) for ... in ...)
打印文本,这真的很难看。它读起来不好。有状态代码应该与语句相关,因为它们提供了副作用的视觉线索。我认为你不会得到比你已经看到的更好的答案。这也让我感到困惑。为什么python在生成器上支持
sum
或all
,而不支持len
?基本上是一样的。PEP或邮件列表中必须有解释……在迭代器上,您会使用len
做什么?要知道它有多长,唯一的方法就是对它进行迭代,所以一旦你知道它有多长(假设它不是无限长的),你就已经消耗了它,并且不能再使用它了