Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/354.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 生成器和列表返回不同的结果_Python_Python 3.x_Generator_Itertools - Fatal编程技术网

Python 生成器和列表返回不同的结果

Python 生成器和列表返回不同的结果,python,python-3.x,generator,itertools,Python,Python 3.x,Generator,Itertools,我试图引入一个生成器,其中每个元素都是一个长度相等的列表/元组/iterable,并为元素的每个索引返回一个单独的生成器 当我硬编码下面的split_feat2中的索引时,它会按预期工作。但是,当我使用列表理解或附加到列表并返回时,它会产生错误的结果 我检查了我的逻辑,并尝试通过在理解中用()替换[]来返回列表列表而不是生成器列表,结果是正确的,因此我不知道问题出在哪里 如果您能深入了解它为什么会这样做,我们将不胜感激 def split_feat2(gen): G = tee(gen,

我试图引入一个生成器,其中每个元素都是一个长度相等的列表/元组/iterable,并为元素的每个索引返回一个单独的生成器

当我硬编码下面的
split_feat2
中的索引时,它会按预期工作。但是,当我使用列表理解或附加到列表并返回时,它会产生错误的结果

我检查了我的逻辑,并尝试通过在理解中用
()
替换
[]
来返回列表列表而不是生成器列表,结果是正确的,因此我不知道问题出在哪里

如果您能深入了解它为什么会这样做,我们将不胜感激

def split_feat2(gen):
    G = tee(gen, 2)
    return [(e[0] for e in G[0]), (e[1] for e in G[1])]

def split_feat(gen, n):
    G = tee(gen, n)
    return [(e[n] for e in g) for n, g in enumerate(G)]

def split_featlist(gen, n):
    G = tee(gen, n)
    return [[e[n] for e in g] for n, g in enumerate(G)]

test = lambda:((i^2,j+i) for i, j in enumerate(range(10)))

print("This is what I want")
t = split_feat2(test())
print(list(t[0]))
print(list(t[1]))
print(t)

print("\nBut I get this output")
t = split_feat(test(), 2)
print(list(t[0]))
print(list(t[1]))
print(t)

print("\nWhen I want this output but from generators instead of lists")
t = split_featlist(test(), 2)
print(list(t[0]))
print(list(t[1]))
print(t)
上述代码输出以下内容:

This is what I want
[2, 3, 0, 1, 6, 7, 4, 5, 10, 11]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
[<generator object split_feat2.<locals>.<genexpr> at 0x00000219C794F7D8>, <generator object split_feat2.<locals>.<genexpr> at 0x00000219C794F200>]

But I get this output
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
[<generator object split_feat.<locals>.<listcomp>.<genexpr> at 0x00000219C791DB48>, <generator object split_feat.<locals>.<listcomp>.<genexpr> at 0x00000219C794F150>]

When I want this output but from generators instead of lists
[2, 3, 0, 1, 6, 7, 4, 5, 10, 11]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
[[2, 3, 0, 1, 6, 7, 4, 5, 10, 11], [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]]
这就是我想要的
[2, 3, 0, 1, 6, 7, 4, 5, 10, 11]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
[, ]
但是我得到了这个输出
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
[, ]
当我想要这个输出,但是来自生成器而不是列表
[2, 3, 0, 1, 6, 7, 4, 5, 10, 11]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
[[2, 3, 0, 1, 6, 7, 4, 5, 10, 11], [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]]

问题在于
n
变量在实际使用发电机之前已经更改。因此,当函数返回生成器列表时,它位于
n-1
(函数参数
n
)。因此,在您的示例中,两个生成器使用相同的索引:
1
。要理解我的意思,请看这个简单的示例:

>>> list_of_list = [[0, 1]]*20
>>> index = 1
>>> gen = (item[index] for item in list_of_list)
>>> print(next(gen))
1
>>> index = 0
>>> print(next(gen))  # changing index "changed the generator"
0
在您的例子中,循环不断地改变(不是像我的例子中那样的手动干预),但是当生成器被执行时,所有创建的生成器的值都是相同的

解决方案 您需要以某种方式为每次迭代“修复”当前值
n
。一种可能性是使用
操作符映射
.itemgetter

def split_feat(gen, n):
    G = tee(gen, n)
    return [map(itemgetter(n), g) for n, g in enumerate(G)]
itemgetter
立即使用“current”
n
值创建,因此结果将与预期一致

这不是实现预期结果的唯一方法。还可以使用创建生成器的函数。该函数将“记住”当前的
n
(就像一个闭包),并且也会像您期望的那样工作:

def split_feat(gen, n):
    G = tee(gen, n)
    def create_generator(it, n):
        return (item[n] for item in it)
    return [create_generator(g, n) for n, g in enumerate(G)]

谢谢很明显,你已经解释了这种行为。顺便说一句,解释得很好。