python 中的 next() 真的那么快吗?

2023-12-22

通过这里的一篇文章,我读到使用 next() 搜索和检索列表中元素的第一次出现可能会很快。然而,我惊讶地发现传统的 for-if-break 语法在相当长一段时间内表现得更好。如果我的分析有错误,请纠正我。 这是我尝试过的一个片段:

>>> def compare_2():
...     device = 'a'
...     l = ['a', 'b', 'c', 'd']
...     z = next((device for x in l if x==device), None)

>>> def compare_1():
...     device = 'a'
...     l = ['a', 'b', 'c', 'd']
...     z = None
...     for x in l:
...             if x == device:
...                     z = device
...                     break

>>> import timeit
>>> t = timeit.Timer(setup='from __main__ import compare_2', stmt='compare_2()')
>>> t.timeit()
1.5207240581512451
>>> t = timeit.Timer(setup='from __main__ import compare_1', stmt='compare_1()')
>>> t.timeit()
0.46623396873474121

我认为这可能会发生,因为我试图搜索和检索列表中的第一个元素作为示例。我还尝试了最后一个元素,并注意到 next() 的性能并不比以前更好。

>>> def compare_2():
...     device = 'd'
...     l = ['a', 'b', 'c', 'd']
...     z = next((device for x in l if x==device), None)
...
>>>
>>> def compare_1():
...     device = 'd'
...     l = ['a', 'b', 'c', 'd']
...     z = None
...     for x in l:
...             if x == device:
...                     z = device
...                     break
...

>>>
>>> t = timeit.Timer(setup='from __main__ import compare_2', stmt='compare_2()')
>>> t.timeit()
1.6903998851776123
>>> t = timeit.Timer(setup='from __main__ import compare_1', stmt='compare_1()')
>>> t.timeit()
0.66585493087768555

很想知道何时实际使用 next() 以及何时不使用,以优化代码。 谢谢!

UPDATE: if device in l肯定会更快。 我实际上只是想制作一个简单案例的原型。我在尝试根据属性匹配从对象列表中检索对象时遇到了这种情况。例如: obj = next(obj 为 obj_list 中的 obj,如果 obj.value == 1)


我想知道是否还有其他事情发生。创建生成器有一些开销,但我认为将条件if x==device在生成器中强制它生成整个列表,并在 next() 运行之前创建一个新列表。

请参阅此示例,比较强制创建新列表的列表推导式和惰性且不强制创建新列表的生成器:

>>> from timeit import Timer
>>> # List comprehension forces a new list to be created in memory
>>> def f1():
...     q = [x for x in xrange(1000)]
...     r = q[1]
...     return r
... 
>>> # Generator comprehension does 'lazy' iteration, only when needed
>>> def f2():
...     q = (x for x in xrange(1000))
...     r = next(q)
...     return r
... 
>>> Timer(f1).timeit()
47.420308774268435
>>> Timer(f2).timeit()
1.346566078497844

看到列表理解要慢得多,并且生成器惰性方法意味着它仅在您调用 next() 时才开始迭代,获取一个值并停止。

现在这个例子,唯一的变化是两者都采用最后一个元素if x = 999:

>>> # List comprehension still forces creation of a new list
>>> # although the list only ends up with one element
>>> # nb. it's the last element
>>> def f1():
...     q = [x for x in xrange(1000) if x == 999]
...     r = q[0]
...     return r
... 
>>> # Generator comprehension is lazy
>>> # nb. it also only returns the last element
>>> def f2():
...     q = (x for x in xrange(1000) if x == 999)
...     r = next(q)
...     return r
... 
>>> Timer(f1).timeit()
37.279105355189984
>>> Timer(f2).timeit()
37.46816399778598

看看现在他们基本是一样的了。发电机的速度已经减慢了。该条件迫使它执行与列表理解相同的操作,它不能懒惰地只获取匹配的一件事情而不评估整个列表。

所以我认为在你的例子中,你不是just看到创建生成器然后在其他人回答时调用它的开销,正如我最初的评论所说。

我认为通过包括if x==device条件,您强制生成器构造迭代整个列表,and创建一个新的列表对象,and用所有结果填充它,then在该新列表上创建一个生成器并then调用它来获取结果。

所以有一个lot比 for 循环迭代现有列表的开销更大,这不是因为next()本质上是缓慢的。

编辑:当生成器表达式被添加到Python中时,您可以在提案中看到它:PEP-0289 - 生成器表达式 https://www.python.org/dev/peps/pep-0289/,在关于的部分早期绑定与后期绑定 https://www.python.org/dev/peps/pep-0289/#early-binding-versus-late-binding

当被要求总结绑定第一个表达式的推理时,Guido 给出了 [5] :

考虑sum(x for x in foo())。现在假设 foo() 中有一个错误 会引发异常,并且 sum() 中的错误会引发 在开始迭代其参数之前发生异常。哪个 您希望看到什么异常?如果其中的一个我会感到惊讶 sum() 被提出,而不是 foo() 中的那个,因为对 foo() 的调用 是 sum() 参数的一部分,我希望参数是 在调用函数之前进行处理。

奥托,在sum(bar(x) for x in foo()),其中 sum() 和 foo() 没有错误,但是 bar() 引发了异常,我们别无选择,只能 延迟对 bar() 的调用,直到 sum() 开始迭代——这就是 发电机合同的一部分。 (他们什么都不做,直到他们 首先调用 next() 方法。)

换句话说,如果x==device将会抛出异常,因为列表中的一项无法比较,例如来自自定义对象的类型错误,您希望在调用 next() 之前看到该异常,从而强制迭代整个列表,失去您可能希望看到的生成器懒惰的节省,并创建更多列表与 for 循环相比,对象创建开销。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python 中的 next() 真的那么快吗? 的相关文章

  • matplotlib 图中点的标签

    所以这是一个关于已发布的解决方案的问题 我试图在我拥有的 matplotlib 散点图中的点上放置一些数据标签 我试图在这里模仿解决方案 是否有与 MATLAB 的 datacursormode 等效的 matplotlib https s
  • NLTK 2.0分类器批量分类器方法

    当我运行此代码时 它会抛出一个错误 我认为这是由于 NLTK 3 0 中不存在batch classify 方法 我很好奇如何解决旧版本中的某些内容在新版本中消失的此类问题 def accuracy classifier gold resu
  • 我应该使用 Python 双端队列还是列表作为堆栈? [复制]

    这个问题在这里已经有答案了 我想要一个可以用作堆栈的 Python 对象 使用双端队列还是列表更好 元素数量较少还是数量较多有什么区别 您的情况可能会根据您的应用程序和具体用例而有所不同 但在一般情况下 列表非常适合堆栈 append is
  • 嵌套列表的重叠会产生不必要的间隙

    我有一个包含三个列表的嵌套 这些列表由 for 循环填充 并且填充由 if 条件控制 第一次迭代后 它可能类似于以下示例 a 1 2 0 0 0 0 0 0 4 5 0 0 0 0 0 0 6 7 根据条件 它们不重叠 在第二次迭代之后 新
  • 从Django中具有外键关系的两个表中检索数据? [复制]

    这个问题在这里已经有答案了 This is my models py file from django db import models class Author models Model first name models CharFie
  • python multiprocessing 设置生成进程等待

    是否可以生成一些进程并将生成进程设置为等待生成的进程完成 下面是我用过的一个例子 import multiprocessing import time import sys def daemon p multiprocessing curr
  • 为什么 web2py 在启动时崩溃?

    我正在尝试让 web2py 在 Ubuntu 机器上运行 所有文档似乎都表明要在 nix 系统上运行它 您需要下载源代码并执行以下操作 蟒蛇 web2py py 我抓住了source http www web2py com examples
  • Haskell:从后面访问列表

    今天我开始学习Haskell 我对函数式语言有点陌生 而且我非常喜欢 Haskell 然而 我有一个关于它的设计的问题困扰着我 从我到目前为止的理解来看 访问列表后面的元素似乎比访问前面的元素要复杂得多 类似于xs x where xs a
  • PyQt 使用 ctrl+Enter 触发按钮

    我正在尝试在我的应用程序中触发 确定 按钮 我当前尝试的代码是这样的 self okPushButton setShortcut ctrl Enter 然而 它不起作用 这是有道理的 我尝试查找一些按键序列here http ftp ics
  • Pycharm 在 os.path 连接上出现“未解析的引用”

    将pycharm升级到2018 1 并将python升级到3 6 5后 pycharm报告 未解析的引用 join 最新版本的 pycharm 不会显示以下行的任何警告 from os path import join expanduser
  • Tensorboard SyntaxError:语法无效

    当我尝试制作张量板时 出现语法错误 尽管开源代码我还是无法理解 我尝试搜索张量板的代码 但不清楚 即使我不擅长Python 我这样写路径C Users jh902 Documents logs因为我正在使用 Windows 10 但我不确定
  • Python 内置的 super() 是否违反了 DRY?

    显然这是有原因的 但我没有足够的经验来认识到这一点 这是Python中给出的例子docs http docs python org 2 library functions html super class C B def method se
  • 无法导入 langchain.agents.load_tools

    我正在尝试使用 LangChain Agents 但无法导入 load tools 版本 langchain 0 0 27 我尝试过这些 from langchain agents import initialize agent from
  • python的shutil.move()在linux上是原子的吗?

    我想知道python的shutil move在linux上是否是原子的 如果源文件和目标文件位于两个不同的分区上 行为是否不同 或者与它们存在于同一分区上时的行为相同吗 我更关心的是如果源文件和目标文件位于同一分区上 shutil move
  • Django 视图中的“请求”是什么

    在 Django 第一个应用程序的 Django 教程中 我们有 from django http import HttpResponse def index request return HttpResponse Hello world
  • Python GTK+ 画布

    我目前正在通过 PyGobject 学习 GTK 需要画布之类的东西 我已经搜索了文档 发现两个小部件似乎可以完成这项工作 GtkDrawingArea 和 GtkLayout 我需要一些基本函数 如 fillrect 或 drawline
  • C# HashSet 只读解决方法

    这是示例代码 static class Store private static List
  • Python:Goslate 翻译请求返回“503:服务不可用”[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我们不允许提出寻求书籍 工具 软件库等推荐的问题 您可以编辑问题 以便用事实和引文来回答 这个问题似乎不是关于主要由程序员使用的特定编程问
  • 如果 PyPy 快 6.3 倍,为什么我不应该使用 PyPy 而不是 CPython?

    我已经听到很多关于PyPy http en wikipedia org wiki PyPy项目 他们声称它比现有技术快 6 3 倍CPython http en wikipedia org wiki CPython口译员开启他们的网站 ht
  • python 对浮点数进行不正确的舍入

    gt gt gt a 0 3135 gt gt gt print 3f a 0 314 gt gt gt a 0 3125 gt gt gt print 3f a 0 312 gt gt gt 我期待 0 313 而不是 0 312 有没有

随机推荐