【问题标题】:Cost of len() functionlen() 函数的成本
【发布时间】:2010-11-10 01:28:24
【问题描述】:

Python 内置函数的len() 函数的成本是多少? (列表/元组/字符串/字典)

【问题讨论】:

    标签: python algorithm collections complexity-theory


    【解决方案1】:

    您提到的每种类型都是 O(1)(恒定时间,不取决于元素的实际长度 - 非常快),加上 set 和其他类型,例如 array.array .

    【讨论】:

    • 感谢您的帮助!是否有任何本机类型不是这种情况?
    • 有趣的是这里只提到了获取长度运行时间 - wiki.python.org/moin/TimeComplexity [未提及其他类型]
    【解决方案2】:

    CPython 中对这些数据类型调用 len() 是 O(1),这是 Python 语言最常见的实现。这是一个表格的链接,该表格提供了 CPython 中许多不同函数的算法复杂性:

    TimeComplexity Python Wiki Page

    【讨论】:

      【解决方案3】:

      所有这些对象都会记录自己的长度。提取长度的时间很短(大 O 表示法中的 O(1))并且主要由 [粗略描述,用 Python 术语而不是 C 术语编写]:在字典中查找“len”并将其发送到内置 len 函数,它将查找对象的 __len__ 方法并调用它......它所要做的就是 return self.length

      【讨论】:

      • 我认为这是最合适的答案,因为它可以深入了解实现细节。
      • 为什么length 没有出现在dir(list) 的字典中?
      • 这就是我要找的东西
      • @ViFI 因为这只是一个例子。图示的 list.lenght 变量是用 C 而非 Python 实现的。
      • 这个解释很中肯,因为它提供了如何确定对象长度的机制。
      【解决方案4】:

      以下测量结果证明len() 对于常用数据结构的复杂度为 O(1)。

      关于timeit 的注意事项:当使用-s 标志并将两个字符串传递给timeit 时,第一个字符串只执行一次且不计时。

      列表:

      $ python -m timeit -s "l = range(10);" "len(l)"
      10000000 loops, best of 3: 0.0677 usec per loop
      
      $ python -m timeit -s "l = range(1000000);" "len(l)"
      10000000 loops, best of 3: 0.0688 usec per loop
      

      元组:

      $ python -m timeit -s "t = (1,)*10;" "len(t)"
      10000000 loops, best of 3: 0.0712 usec per loop
      
      $ python -m timeit -s "t = (1,)*1000000;" "len(t)"
      10000000 loops, best of 3: 0.0699 usec per loop
      

      字符串:

      $ python -m timeit -s "s = '1'*10;" "len(s)"
      10000000 loops, best of 3: 0.0713 usec per loop
      
      $ python -m timeit -s "s = '1'*1000000;" "len(s)"
      10000000 loops, best of 3: 0.0686 usec per loop
      

      字典(字典理解在 2.7+ 中可用):

      $ python -mtimeit -s"d = {i:j for i,j in enumerate(range(10))};" "len(d)"
      10000000 loops, best of 3: 0.0711 usec per loop
      
      $ python -mtimeit -s"d = {i:j for i,j in enumerate(range(1000000))};" "len(d)"
      10000000 loops, best of 3: 0.0727 usec per loop
      

      数组:

      $ python -mtimeit -s"import array;a=array.array('i',range(10));" "len(a)"
      10000000 loops, best of 3: 0.0682 usec per loop
      
      $ python -mtimeit -s"import array;a=array.array('i',range(1000000));" "len(a)"
      10000000 loops, best of 3: 0.0753 usec per loop
      

      集合(集合理解在 2.7+ 中可用):

      $ python -mtimeit -s"s = {i for i in range(10)};" "len(s)"
      10000000 loops, best of 3: 0.0754 usec per loop
      
      $ python -mtimeit -s"s = {i for i in range(1000000)};" "len(s)"
      10000000 loops, best of 3: 0.0713 usec per loop
      

      双端队列:

      $ python -mtimeit -s"from collections import deque;d=deque(range(10));" "len(d)"
      100000000 loops, best of 3: 0.0163 usec per loop
      
      $ python -mtimeit -s"from collections import deque;d=deque(range(1000000));" "len(d)"
      100000000 loops, best of 3: 0.0163 usec per loop
      

      【讨论】:

      • 这并不是一个很好的基准,尽管它显示了我们已经知道的内容。这是因为 range(10) 和 range(1000000) 不应该是 O(1)。
      • 这是迄今为止最好的答案。您应该添加一个结论,以防有人没有意识到恒定的时间。
      • 感谢您的评论。我添加了关于 len() 的 O(1) 复杂性的注释,并修复了测量以正确使用 -s 标志。
      • 重要的是要注意,将长度保存到变量中可以节省大量的计算时间:python -m timeit -s "l = range(10000);" "len(l); len(l); len(l)" 223 nsec 每循环 python -m timeit -s "l = range(100);" "len(l)" 66.2 nsec 每循环
      【解决方案5】:

      len 是 O(1),因为在您的 RAM 中,列表存储为表(一系列连续地址)。要知道表何时停止计算机需要两件事:长度和起点。这就是为什么 len() 是一个 O(1) 的原因,计算机存储了这个值,所以它只需要查找它。

      【讨论】:

        猜你喜欢
        • 2015-06-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-18
        • 1970-01-01
        • 2014-11-01
        相关资源
        最近更新 更多