Python 为什么我不想立即将所有的iterables转换为具有定义长度的内容(例如列表)?
我不知道为什么我不总是转换成列表。为什么我不想立即将所有iterables转换为具有定义长度的内容(如列表)?欢迎加入社区Python 为什么我不想立即将所有的iterables转换为具有定义长度的内容(例如列表)?,python,Python,我不知道为什么我不总是转换成列表。为什么我不想立即将所有iterables转换为具有定义长度的内容(如列表)?欢迎加入社区 “将iterable转换为列表”通常是一种O(N)/线性操作 “处理列表中的所有元素”通常是一种O(N)/线性操作 在对iterable进行操作之前,通常不应将其转换为列表的原因是,对于只需执行N操作的对象,iterable将执行2*N操作 (正如一些用户在评论中有益地提到的那样,这里存在一些对大O复杂度表示法的严重滥用。对于时间复杂度界限,我们忽略常数,而将重点放在与极限
O(N)
/线性操作O(N)
/线性操作N
操作的对象,iterable将执行2*N
操作
(正如一些用户在评论中有益地提到的那样,这里存在一些对大O复杂度表示法的严重滥用。对于时间复杂度界限,我们忽略常数,而将重点放在与极限中类似算法相比的行为上。这里我们将重点放在一个特定的案例上,并对其中一些算法的性能进行基准测试在实践中。)
以下是我们感兴趣的两个案例:
def compute_over_iterable():
“”“将'values'初始化为iterable,并对其进行计算。”“”
值=范围(10000)
结果=[]
对于输入值:
结果.追加(条目+1)
返回结果
def compute_over_iterable_to_list():
“”“将`values`初始化为iterable,转换为列表,然后计算:”“”
值=列表(范围(10000))
结果=[]
对于输入值:
结果.追加(条目+1)
返回结果
通过pytest benchmark
,我们可以看到这些案例的执行情况:
----------------------------------- benchmark: 2 tests -----------------------------------
Name (time in us) Min Max Mean
------------------------------------------------------------------------------------------
test_iterable 781.3790 (1.0) 1,118.6880 (1.0) 837.1683 (1.0)
test_iterable_to_list 1,000.4090 (1.28) 1,524.6950 (1.36) 1,138.6464 (1.36)
------------------------------------------------------------------------------------------
在本例中,我们看到(2)将iterable转换为列表所需的时间比直接使用iterable要长约1.36倍
由于list(范围(10000))
cast是在Python的底层C实现中处理的,因此这两种方法的结果非常接近。如果完全在Python中执行此操作,则差异更为明显:
def compute_over_iterable_list_comprehension():
值=范围(10000)
值\u cast=[i代表值中的i]
结果=[]
对于值中的输入\u cast:
结果.追加(条目+1)
返回结果
我们看到,直接使用iterable需要约1.5倍的时间:
------------------------------------------ benchmark: 3 tests ------------------------------------------
Name (time in us) Min Max Mean
--------------------------------------------------------------------------------------------------------
test_iterable 844.9320 (1.0) 1,014.3210 (1.0) 896.8944 (1.0)
test_iterable_to_list 1,079.2420 (1.28) 1,370.0570 (1.35) 1,140.3908 (1.27)
test_iterable_to_list_comprehension 1,269.8290 (1.50) 1,662.9790 (1.64) 1,336.5758 (1.49)
--------------------------------------------------------------------------------------------------------
一些例外和有趣的案例
MemoryView
“@user2357112支持Monica”,我不熟悉。它涉及:
“这通常需要一个对象,该对象具有将其转换为列表的方法,而不仅仅是调用列表。它仍然会浪费内存,通常不会节省很多时间,因此通常不值得费心。”
出于好奇,我将这些添加到了一个单独的基准中。下面是一个基本概述,重点介绍了三种情况:
def compute_over_memory_view():
值=内存视图(b'x'*10000)
# ...
def compute_over_memory_view_tolist():
值=内存视图(b'x'*10000)
对于values.tolist()中的条目:
# ...
def compute_over_memory_view_cast():
值=内存视图(b'x'*10000)
值\u cast=列表(值)
# ...
我的基准测试似乎表明,在memoryview对象上调用tolist
方法与直接在memoryview上操作几乎没有区别,但相比之下,转换到列表(list(values)
)要慢得多
-------------------------- benchmark 'Memory Views': 3 tests ---------------------------
Name (time in us) Min Mean Max
----------------------------------------------------------------------------------------
test_memory_view 711.5030 (1.0) 774.2104 (1.0) 990.5890 (1.0)
test_memory_view_tolist 745.4060 (1.05) 822.1782 (1.06) 1,154.2550 (1.17)
test_memory_view_cast 860.5850 (1.21) 995.6708 (1.29) 1,290.4440 (1.30)
----------------------------------------------------------------------------------------
无限长不可数
“@Tomerikoo”提出了另一个很好的观点:iterable可以是无限的。在这种情况下,试图将iterable转换为有限长度的东西会让你陷入无限循环
下面是一个最简单的示例:
来自itertools导入周期的>>
>>>从时间上导入睡眠
>>>对于循环中的i(范围(3)):
…睡眠(0.5)
…印刷品(一)
...
0
1.
2.
0
1.
2.
0
我们已经讨论过,“将iterable转换为list”是一个需要遍历list的所有元素的操作。
因此,以下语句是一个无限循环:
列表(循环(范围(3))
当源数据太大而无法放入内存时会发生什么情况?特别是如果您可以以原子方式处理数据,则无需分配所有内存(并可能会破坏RAM)你为什么要这样做?通常,实际上大多数时候,我只需要迭代一个iterable。我不关心它的长度。假设我使用的是像
映射
对象这样的东西。为什么不必要地浪费内存来将它转换成一个列表?我想这是对的。谢谢你的帮助。另外一个想法:如果你的数据需要一段时间来计算,你可以如果你一次只需要一个元素,你不想花那么多时间计算列表中的所有元素。你可以处理每一个元素,同时计算更多元素。iterable没有大小的元素是什么?假设你在重复轮询某个元素,或者只是使用一个无限生成器(如itertools.count
)。不可能将其放入列表中,正如其他人所说,为什么您甚至希望将其作为列表?大多数情况下,我们只需要对某些内容进行迭代。然后使用迭代器而不是列表,不,对不起,但这是不正确的。因此,假设您有类似于data=map的内容(some\u func,some\u iterable)
。如果对数据中的x执行操作:执行某事(x)
,假设执行某事和某些函数在固定时间内工作,整个算法是线性时间。如果首先转换为列表,它仍然是线性时间,例如数据=列表(数据);对于数据中的x:执行某事(x)
。它只会是O(N**2)如果你在每次迭代中都进行这种转换,这通常是没有意义的(尽管我在“野外”看到过更疯狂的事情),做两个O(N)的事情仍然是O(N)。如果你做的事情时间与N成正比,与N成正比,那么这就是O(N^2).谢谢你的关注,我已经用标签写了一个快速的基准来演示这个,但没有抓住m