Python:itertools.chain.from_iterable

时间:2016-01-26 19:26:23

标签: python itertools

请考虑以下代码段:

>>> from itertools import chain
>>> foo = [0]
>>> for i in (1, 2):
...     bar = (range(a, a+i) for a in foo)
...     foo = chain(*list(bar))
...
>>> list(foo)
[0, 1]

这是有道理的 - 在循环的第一次迭代中,bar等同于iter([[0]]),foo的计算结果为chain([0]),相当于iter([0])。然后,在循环的第二次迭代中,bar现在等同于iter([[0, 1]]),foo变为iter([0, 1])。这就是list(foo)[0, 1]的原因。

当我使用list(foo)而不是foo = sum(list(bar), [])时,我也会得到与chain(*list(bar))相同的结果。

现在考虑一下这段代码:

>>> from itertools import chain
>>> foo = [0]
>>> for i in (1, 2):
...     bar = (range(a, a+i) for a in foo)
...     foo = chain.from_iterable(bar)
...
>>> list(foo)
[0, 1, 1, 2]

正如您所看到的,唯一的区别是使用itertools.chain.from_iterable而不是foo = chain.from_iterable(bar)的{​​{1}}行。

在我看来,itertools.chain大致相当于itertools.chain(*list(iterable)),但在此情况并非如此。那么为什么最终的结果不同呢?

2 个答案:

答案 0 :(得分:5)

不同之处在于chain(*list(bar))中,条形图立即耗尽,而chain.from_iterable(bar)中则不是。bari的定义中,使用i,它是后期绑定:它在定义时不是i的值,而是从名称{{1}中获取foo = chain.from_iterable(bar)的值在它被评估的时候。

IOW,当您使用bar时,list(foo)尚未评估。然后,当您拨打bar时,它会呼叫" i,定义中的i会获取名称i 当前引用的值 - 即2。

因此,如果我们手动更改>>> from itertools import chain >>> foo = [0] >>> for i in (1, 2): ... bar = (range(a, a+i) for a in foo) ... foo = chain.from_iterable(bar) ... >>> i = 10 >>> list(foo) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18] ,我们应该能够适当地更改结果:

def inputnumber() :
    x = input('pick a number : ')
    if x == 17 :
        raise 'BadNumberError' , '17 is a bad number'
    return x

答案 1 :(得分:0)

不同之处在于使用生成器和foo = chain.from_iterable(list(bar))的延迟评估。如果您将此行更改为list(foo),这两个程序将是等效的,这会强制条形码生成器的评估以具体值为基础foo。

否则,如上所述,这两个程序在语义上是不同的,因为前者将链应用于列表,而第二个程序将链应用于生成器,在某些方面可以将其视为函数句柄,这将执行推迟到最终循环结束后调用 import processing.core.*; import java.awt.*; import ddf.minim.signals.*; import ddf.minim.*; import ddf.minim.analysis.*; import ddf.minim.effects.*; public class MinimTest2 extends PApplet { Minim minim; FFT fft; AudioInput in; float[] amp = new float[430]; float[] temp; public void settings() { size(800, 600); } public MinimTest2() { minim = new Minim(this); in = minim.getLineIn(); fft = new FFT(in.bufferSize(), in.sampleRate()); } public float[] getAmps(){ fft.forward(in.left); amp = new float[430]; temp = new float[fft.specSize()]; int index = 0; for (int k=0; k<fft.specSize(); k++){ temp[index]=fft.getBand(k); index++; } for (int i=0; i<amp.length; i++) amp[i]=temp[i]; return amp; } public int getFFTSize(){ return fft.specSize(); } }

[这个答案在Python 3中测试过,其中range是一个生成器。它可能在Python 2.x中表现不同,其中range返回整个列表...]