使用元组过滤和拆包处理空情况

Handling empty case with tuple filtering and unpacking

我遇到一些并行列表需要根据其中一个列表中的值进行过滤的情况。有时我会写这样的东西来过滤它们:

lista = [1, 2, 3]
listb = [7, 8, 9]
filtered_a, filtered_b = zip(*[(a, b) for (a, b) in zip(lista, listb) if a < 3])

这给出 filtered_a == (1, 2)filtered_b == (7, 8)

但是,将最终条件从 a < 3 更改为 a < 0 会引发异常:

Traceback (most recent call last):
  ...
ValueError: need more than 0 values to unpack

我知道为什么会这样:列表理解是空的,所以它就像调用 zip(*[]),就像 zip(),只是 returns 一个空列表,不能解压到单独的 filtered_a 和 filtered_b 迭代器中。

是否有更好的(更短、更简单、更pythonic)处理空案例的过滤函数?在空的情况下,我希望 filtered_a 和 filtered_b 是空的可迭代对象,因此任何后续代码都可以保持不变。

我可能会这样做:

lista = [1, 2, 3]
listb = [7, 8, 9]

filtered_abs = ((a, b) for (a, b) in zip(lista, listb) if a < 3])

for a, b in filtered_abs:
    do_thing(a, b)

您可以使用默认值 短路

filtered_a, filtered_b = zip(*[(a, b) for a, b in zip(lista, listb) if a < 0]) or ([], [])
print(filtered_b, filtered_a)
# [] []

对于 Python 3,您需要在 zip 返回的迭代器上调用 list 以便第一个操作数可以被评估为空列表(不是迭代器) ,否则即使迭代器可能为空,也永远不会达到默认值,因为 bool(iter([]))True.