为何Python的list()会调用对象的__len__()方法?
为何Python的list()会调用对象的__len__()方法?
这个问题问得好!我当初刚接触Python的魔法方法时也懵过,咱们一步步拆解来看。
首先得说清楚为什么list()会触发__len__调用:
这完全是Python为了性能优化做的手脚。你想啊,当你用list()把一个可迭代对象转成列表时,如果这个对象不仅能被迭代(实现了__iter__),还能返回自己的长度(实现了__len__),那Python就可以先调用__len__知道元素总数,然后一次性分配刚好能装下所有元素的内存空间——要是不这么做,list只能从默认大小开始,迭代一个元素就append一个,空间不够了再扩容,每次扩容都要重新分配内存、复制现有元素,效率低多了。预分配空间能省掉这些额外开销,这是个很实用的优化。
结合你的代码例子来看:
你的MyContainer类既实现了__iter__(满足可迭代的要求),又实现了__len__,所以list()处理它的时候,就会先调用__len__拿到3,初始化一个长度为3的空列表,再调用__iter__获取迭代器把元素填进去,所以你才会看到__iter__和__len__都被调用了。而你之前用已经生成的迭代器i转列表时,迭代器本身是没有__len__方法的(你可以试试len(i),肯定会报错),list()没法预分配空间,只能边迭代边扩容,自然不会触发__len__调用。
再说说文档在哪里:
这个行为在Python官方文档里是有明确说明的:
- 在
list()构造函数的说明中,提到当传入的可迭代对象实现了__len__时,会利用该方法来优化内存分配; - 另外在Python数据模型文档里,关于__len__方法的描述也提到,容器类型实现__len__是为了让内置函数和操作符能利用它来提升性能,list()就是其中一个典型场景。
备注:内容来源于stack exchange,提问作者odigity
相关产品推荐
相关产品推荐

