返回迭代器的可怕的“节省空间”版本:
from itertools import tee
ay, by = [(r[i] for r in results) for i, results in enumerate(tee(map(calc, steps), 2))]
但基本上只是使用zip
,因为大多数时候它不值得丑陋。
解释:
zip(*(calc(x) for x in steps))
将做得到(calc(x) for x in steps)
一个迭代器[(2, 1), (4, 4), (6, 9), (8, 16), (10, 25)]
。
当您打开包装时,您执行的操作相当于
zip((2, 1), (4, 4), (6, 9), (8, 16), (10, 25))
所以所有的项目都一次存储在内存中。证明:
def return_args(*args):
return args
return_args(*(calc(x) for x in steps))
#>>> ((2, 1), (4, 4), (6, 9), (8, 16), (10, 25))
因此,所有项目一次都在内存中。
那么我的工作原理是怎样的呢?
map(calc, steps)
与(calc(x) for x in steps)
(Python 3) 相同。这是一个迭代器。在 Python 2 上,使用imap
or (calc(x) for x in steps)
。
tee(..., 2)
获得两个存储迭代差异的迭代器。如果您以同步方式迭代,tee
则将占用O(1)
内存。如果不这样做,则tee
最多可以占用O(n)
. 所以现在我们有一个用法,可以让我们拥有到目前为止的O(1)
内存。
enumerate
显然会将其保存在不断的记忆中。
(r[i] for r in results)
返回一个迭代器,它从每个结果中获取第i
th项。这意味着在这种情况下,它会收到一对(依次为 so r=(2,1)
、等)。r=(4,4)
它返回特定的迭代器。
因此,如果您进行迭代ay
并且by
步调一致,将使用常量内存。内存使用量与迭代器之间的距离成正比。这在许多情况下很有用(想象一下对文件进行比较或诸如此类),但正如我大部分时间所说的那样,它不值得丑陋。还有一个额外的常数因子开销。