当前位置: 首页 > 面试题库 >

为什么列表询问__len__?

金令秋
2023-03-14
问题内容
class Foo:
    def __getitem__(self, item):
        print('getitem', item)
        if item == 6:
            raise IndexError
        return item**2
    def __len__(self):
        print('len')
        return 3

class Bar:
    def __iter__(self):
        print('iter')
        return iter([3, 5, 42, 69])
    def __len__(self):
        print('len')
        return 3

演示:

>>> list(Foo())
len
getitem 0
getitem 1
getitem 2
getitem 3
getitem 4
getitem 5
getitem 6
[0, 1, 4, 9, 16, 25]
>>> list(Bar())
iter
len
[3, 5, 42, 69]

为什么要list打电话__len__?似乎没有将结果用于任何显而易见的事情。一个for循环不会做。在迭代器协议的任何地方都没有提到这点,只是讨论__iter____next__

这是Python预先为列表保留空间还是类似的东西?

(Linux上的CPython 3.6.0)


问题答案:

请参阅PEP
424
的“基本原理”部分,该部分介绍__length_hint__并提供了有关动机的见解:

能够根据预期大小(由估算)预先分配列表__length_hint__可能是一项重大优化。
观察到CPython比PyPy运行某些代码快,完全是因为存在这种优化。

除此之外,用于的文档还object.__length_hint__验证了这纯粹是一项优化功能:

叫执行operator.length_hint()。应该返回对象的估计长度(可以大于或小于实际长度)。长度必须是整数>= 0此方法
纯粹是一种优化 ,对于正确性从来不需要

__length_hint__之所以如此,是因为它可以带来一些不错的优化。

PyObject_LengthHint,首先尝试从中获取值object.__len__
(如果已定义),然后尝试查看是否object.__length_hint__可用。如果两者都不存在,则返回8for列表的默认值。

listextend``list_init如Eli在其答案中所述被调用,根据此PEP进行了修改,以为定义a__len__或a的任何内容提供此优化__length_hint__

list不是唯一受益于此的bytes对象,对象当然可以这样做:

>>> bytes(Foo())
len
getitem 0
...
b'\x00\x01\x04\t\x10\x19'

对象也是如此,bytearray但只有当您使用extend它们时:

>>> bytearray().extend(Foo())
len
getitem 0
...

tuple创建中间序列以填充自身的对象:

>>> tuple(Foo())
len
getitem 0
...
(0, 1, 4, 9, 16, 25)

如果有人在徘徊,为什么在上课 之前 而不是在上课之后'iter'打印确切的内容: __'len'``Bar``Foo

这是因为如果手中的对象定义了__iter__ Python, 则将首先调用它
来获取迭代器,从而也运行它print('iter')。如果回到使用,则不会发生相同的情况__getitem__



 类似资料:
  • 所以我的问题是为什么not Queue比list更受欢迎。我相信一定有某种原因,但不知何故,我错过了这种理解? 更新:-这是我明确的要求 1)加法发生在末尾,应该很快。可能是O(1) 3)由于查找将基于om索引进行,因此两者都将是O(1)

  • 我现在想要一个数据结构,就像一个有索引的Deque。因此,它应该有O(1)在前面和后面添加和删除元素,以及O(1)基于索引访问元素。这并不难想象一个适合这种情况的设置。 ArrayDeque似乎是一个自然的选择。但是,ArrayDeque不实现List。由于底层数据结构是一个数组,是否有充分的理由不允许索引? 还有,更实用的是,有人知道有哪个图书馆在做我想做的事情吗。据我所知,Apache Com

  • 我已经用reduce内置函数编写了这些代码行,但它显示了给定参数的错误。 45 lst=[1,2,3]中的TypeError回溯(最近一次调用)---- TypeError:d_n()接受1个位置参数,但给出了2个

  • 我使用的是Spring Boot 2.3.4/Spring Data/Hibernate/MySQL8。 我的数据库表称为“ProductDef”。我有一个实体对象“ProductDef”。 当我执行“全部列表”查询时,我得到了这个错误... 我尝试将注释添加到实体中,但没有帮助。 如果我将db表重命名为“PRODUCT_DEF”,我的代码就可以工作了。但不幸的是,我不能为我的项目重命名db表名。

  • 问题内容: 中的运算符似乎在列表上运行异常。谁能告诉我这是怎么回事? 输出值 似乎影响类的每个实例,而似乎以我希望事情表现的方式表现。 该+=运算符称为“化合物赋值运算符”。 问题答案: 一般的答案是+=尝试调用特殊方法,如果该方法不可用,它将尝试使用替代方法。因此,问题在于这些特殊方法之间的差异。 的特殊方法是就地此外,这是它发生变异,它作用于对象。该特殊方法返回一个新的对象,也可用于标准+操作