Python';s itertools.compress的工作方式与布尔掩码不同。为什么?

Python';s itertools.compress的工作方式与布尔掩码不同。为什么?,python,itertools,Python,Itertools,我有一个字符串列表,我想使用itertools.compress过滤给定的布尔掩码 我有大量的字符串需要对照句子列表进行检查。因此,我希望使用itertools节省资源。不按预期工作的部分是通过压缩的布尔掩蔽 来自itertools导入产品、星图、压缩 def在(字符串,其他字符串)中: 返回其他_字符串中的字符串 to_find=['hello','bye'] 一些句子=[“你好”,“你好,再见”,“再见”] 笛卡尔=积(为了寻找,一些句子) 匹配的_掩码=星图(在笛卡尔坐标系中) 匹配=压缩

我有一个字符串列表,我想使用
itertools.compress
过滤给定的布尔掩码

我有大量的字符串需要对照句子列表进行检查。因此,我希望使用itertools节省资源。不按预期工作的部分是通过压缩的布尔掩蔽

来自itertools导入产品、星图、压缩
def在(字符串,其他字符串)中:
返回其他_字符串中的字符串
to_find=['hello','bye']
一些句子=[“你好”,“你好,再见”,“再见”]
笛卡尔=积(为了寻找,一些句子)
匹配的_掩码=星图(在笛卡尔坐标系中)
匹配=压缩(笛卡尔,匹配的_掩码)
打印(列表(匹配))
react_result=[('hello','hello to you'),('bye','hello and bye')]
预期=[('hello','hello to you'),
(“你好”,“你好,再见”),
(‘再见’、‘你好,再见’),
(‘再见’、‘再见’)]
返回迭代器,迭代器通常是“单次传递”(可能有例外)。一旦元素被迭代,它就不会被再次迭代

但是,您可以在两个位置使用
itertools.product
的结果,一个作为
starmap
的参数,另一个作为
compress
的参数。因此,如果
starmap
产品中“弹出”一个元素,那么下次
压缩
时,将从同一产品中“弹出”一个元素,它将接收下一个元素(不是同一个元素)

在大多数情况下,我建议不要将这些迭代器指定为变量,正是因为它们的“单次传递”特性

因此,一个明显的解决办法是生成两次产品:

matched_mask = starmap(is_in, product(to_find, some_sentences))
matched = compress(product(to_find, some_sentences), matched_mask)
print(list(matched))
# [('hello', 'hello to you'), ('hello', ' hello and bye'), ('bye', ' hello and bye'), ('bye', 'bye bye')]
在这种情况下,我认为生成器函数中的循环比使用多个
itertools
更具可读性:

from itertools import product

def func(to_find, some_sentences):
    for sub, sentence in product(to_find, some_sentences):
        if sub in sentence:
            yield sub, sentence
然后像这样使用它:

>>> to_find = ['hello','bye']
>>> some_sentences = ['hello to you', ' hello and bye', 'bye bye']
>>> list(func(to_find, some_sentences))
[('hello', 'hello to you'), 
 ('hello', ' hello and bye'), 
 ('bye', ' hello and bye'), 
 ('bye', 'bye bye')]
或者,如果您喜欢一行:

>>> [(sub, sentence) for sub, sentence in product(to_find, some_sentences) if sub in sentence]
[('hello', 'hello to you'),
 ('hello', ' hello and bye'),
 ('bye', ' hello and bye'),
 ('bye', 'bye bye')]

Product返回一个迭代器,该迭代器只对每个元素迭代一次。因此,您不能两次使用它(一次在星图中,一次在压缩中)。您不能重复使用迭代器,它是单次传递“可能有异常”->,出于好奇,您在考虑什么情况?迭代器的定义要求它在
\uuuuu iter\uuu中返回
self
,并实现
\uuuuuu next\uu
。但是,它并没有说明它可能只定义这两种方法,或者允许
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。你可以想象在
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
中的实现实际上多次返回同一项。或者您甚至可以添加一个名为
go\u back\u one\u element
的方法,并在每次迭代后调用它。当然还有
itertools.tee
(不完全是多次传递,但它返回多个迭代器,允许在一个迭代器上多次迭代)。@BradSolomon一个众所周知的例外是文件的迭代器-如果基础文件允许在EOF之后读取,迭代器将在引发
StopIteration
后愉快地生成新行。看看这个例子。