我在Python 3.5中具有这段代码,该代码实现了用于生成可能较大的缓冲数据批处理的生成器:
def batched_data(data, size=20):
batch = []
for d in data:
batch.append(d)
if len(batch) == size:
yield batch
batch.clear()
yield batch
def buffered_data(data, bufminsize=10, bufmaxsize=20):
diter = iter(data)
buffer = collections.deque(next(diter) for _ in range(bufmaxsize))
while buffer:
yield buffer.popleft()
if len(buffer) < bufminsize:
buffer.extend(
next(diter) for _ in range(bufmaxsize - len(buffer)))
def batched_buffered_data(data, bufsize=100, batch=20):
yield from batched_data(
buffered_data(data, bufmaxsize=bufsize,
bufminsize=bufsize - batch),
size=batch)
现在,当我初始化生成器并在for循环中遍历批处理时,一切都很好:
In [351]: gen = batched_buffered_data(range(27), bufsize=10, batch=7)
In [352]: for g in gen:
...: print(g)
...:
[0, 1, 2, 3, 4, 5, 6]
[7, 8, 9, 10, 11, 12, 13]
[14, 15, 16, 17, 18, 19, 20]
[21, 22, 23, 24, 25, 26]
但是,当我尝试使用列表理解或通过list
进行转换时,会发生这种情况:
In [353]: gen = batched_buffered_data(range(27), bufsize=10, batch=7)
In [354]: list(gen)
Out[354]:
[[21, 22, 23, 24, 25, 26],
[21, 22, 23, 24, 25, 26],
[21, 22, 23, 24, 25, 26],
[21, 22, 23, 24, 25, 26]]
我对此感到非常困惑。必须涉及某种可变元素,但我真的不知道这种行为的背后是什么。
答案 0 :(得分:2)
将batch.clear()
更改为batch = []
应该可以解决。问题是batch
之后的clear()
列表仍然是对一个原始列表的引用。产量似乎起作用,因为它正在打印一个列表,该列表是在更改下一个yield
上的元素之前显示的。在每个yield
上将其设置为新列表会破坏对上一次迭代的引用,因此不会出现别名。
如果您仍然感到困惑,请使用带有.clear()
的原始代码来查看此示例:
result = []
gen = batched_buffered_data(range(27), bufsize=10, batch=7)
for g in gen:
result.append(g)
[print(x) for x in result]
输出:
[21, 22, 23, 24, 25, 26]
[21, 22, 23, 24, 25, 26]
[21, 22, 23, 24, 25, 26]
[21, 22, 23, 24, 25, 26]
答案 1 :(得分:2)
您应将batch.clear()
更改为batch = []
。
这是因为.clear()
清除了列表,指向该列表的所有变量都变成了[]
,否则batch = []
只是创建了一个新列表并将其分配给批处理