- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
通过这里的一篇帖子,我了解到使用 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() 以及何时不使用。谢谢!
更新:if device in l
肯定会更快。我实际上只是想制作一个简单案例的原型(prototype)。我在尝试根据属性匹配从对象列表中检索对象时遇到此问题。例如:obj = next(obj for obj in obj_list if 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
看他们现在基本一样了。发电机已经减速了。条件迫使它做与列表理解相同的事情,它不能在不评估整个列表的情况下懒惰地只接受一个匹配的东西。
所以我认为在您的示例中,您不是只是看到创建生成器然后在其他人回答时调用它的开销,正如我最初的评论所说。
我认为通过包含 if x==device
条件,您将强制生成器构造迭代整个列表,并创建一个新的列表对象,< em>并用所有结果填充它,然后在那个新列表上创建一个生成器,然后调用它来获取结果。
因此,与遍历现有列表的 for 循环相比,很多的开销要大,这并不是因为 next()
本身就很慢。
编辑:您可以在将生成器表达式添加到 Python 的提案中看到它:PEP-0289 - Generator Expressions , 在关于 Early Binding vs Late Binding 的部分
Asked to summarize the reasoning for binding the first expression, Guido offered [5] :
Consider
sum(x for x in foo())
. Now suppose there's a bug in foo() that raises an exception, and a bug in sum() that raises an exception before it starts iterating over its argument. Which exception would you expect to see? I'd be surprised if the one in sum() was raised rather the one in foo(), since the call to foo() is part of the argument to sum(), and I expect arguments to be processed before the function is called.OTOH, in
sum(bar(x) for x in foo())
, where sum() and foo() are bugfree, but bar() raises an exception, we have no choice but to delay the call to bar() until sum() starts iterating -- that's part of the contract of generators. (They do nothing until their next() method is first called.)
换句话说,如果 x==device
将抛出异常,因为无法比较列表中的一项,例如来自自定义对象的类型错误,您可能希望在调用 next() 之前看到该异常,从而强制迭代整个列表,失去您可能希望看到的生成器惰性的保存,并创建更多列表对象创建开销与 for 循环相比。
关于python - python 中的 next() 真的那么快吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31040017/
我正在尝试在两个表之间进行空间连接: 表 1:397265 个特征(在 geom 字段上有 gist 索引) 表 2:73 个特征(在 geom 字段上有 gist 索引) 表 1 和表 2 具有相同
我正在尝试在两个表之间进行空间连接: 表 1:397265 个特征(在 geom 字段上有 gist 索引) 表 2:73 个特征(在 geom 字段上有 gist 索引) 表 1 和表 2 具有相同
枚举类型的值是该类型的静态变量。 据我所知,变量是由引用变量引用的,但没有新的运算符来实例化枚举对象。但这就像初始化数组一样吗? 这是对还是错? 最佳答案 是的,枚举类型的文字是 public sta
我阅读了有关关闭 zsh 自动更正以完成命令的所有提示。但是,它们并没有完全发挥作用。我试过 DISABLE_CORRECTION="true", unsetopt correct, unsetopt
我知道这个问题是 answered before ,但给出的答案并不是完整的故事: 我进入了 Firefox 的 Options->Content 并删除了除德语/德国之外的所有语言,navigato
我知道用汇编语言编写任何内容或将汇编语言添加到任何程序都会损害其可移植性。但是,有多糟糕呢?我的意思是,现在基本上所有 PC 都是 x86 或 x64,对吧?那么,如果我将汇编嵌入到 C 程序中,为什
我正计划构建一个 Web 服务客户端,它始终检查数据库中的某些记录,并根据数据库内容的结果在每个时刻及时执行某些决策。 所以我在想,我怎样才能让客户端一直运行呢? 我唯一想到的就是无限循环。像这样的东
我无法获取小部件的实际背景颜色。在我的特殊情况下,我在使用 QTabWidget 中的小部件时遇到了问题。 这是在 Windows7 上。所以经典小部件有一些灰色背景,而选项卡中的小部件通常用白色背景
请不要将我指向How to wrap preference title?因为它不适用于(正如我评论的那样)您使用 @strings/ 的情况对 strings.xml 文件的引用。 如果你使用 and
情况如下: 已知hdfs是仅附加的(本身没有更新)。 配置单元将数据写入其位于hdfs中的仓库。 可以在配置单元中执行更新 这意味着写入了新数据,旧数据应该以某种方式标记为已弃用,然后在某个时间将其清
在javascript中删除cookies的方法是将过期日期设置为过去。现在这实际上并没有删除 cookie,至少在 Firefox 中是这样。这只是意味着 cookie 将在浏览器关闭时被删除。 这
我需要终止一个卡住的线程,我将 IsBackground 设置为 true 但它仍然存在。线程的属性: ThreadState = AbortRequested IsBackground = true
在逻辑中,以及在 *ahem* 正确设计的编程语言中,将 boolean 值与 true 进行比较总是多余的,即 a == True 应该简单地替换为 a 。 (类似地, a == False 由 n
我一直在努力寻找一个好的定义,并理解线程到底是什么。 看来我一定错过了一些明显的东西,但是每次我读到什么是线程时,它几乎是一个循环定义,la“线程是一个执行线程”或“一种划分运行任务的方法” ”。呃呃
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
是否可以在 MAC 上以真正的全屏模式运行 IntelliJ Idea? 没有工具栏、侧边栏、按钮,只有代码。 如果可以,请告诉我。 最佳答案 您可以通过禁用以下项目在 View 菜单中执行此操作:
考虑以下代码: case class Vector3(var x: Float, var y: Float, var z: Float) { def add(v: Vector3): Unit =
我试图确认这个说法是否属实: 模型包括: 持久层:本质上是 DAO + 表示表的类 + DTO 服务层:DAOS + 一些逻辑的组合 您能否也引用/支持您的回答?我相信我在Spring Framewo
给定代码: #include struct X {}; struct Y1: virtual X {}; struct Y2: virtual X {}; struct Y3: virtual X
从这个其他QUESTION他们谈论 Bjarne Stroustrup 是如何说的,就像比 int 窄的整数数据类型(例如 short)被提升为 int,float 被提升为 double。但是,与i
我是一名优秀的程序员,十分优秀!