泛舟湖上清波郎朗
这可以满足您的要求,并且几乎可以在所有情况下使用:>>> all(x in ['b', 'a', 'foo', 'bar'] for x in ['a', 'b'])True该表达式'a','b' in ['b', 'a', 'foo', 'bar']无法按预期工作,因为Python将其解释为元组:>>> 'a', 'b'('a', 'b')>>> 'a', 5 + 2('a', 7)>>> 'a', 'x' in 'xerxes'('a', True)其他选择还有其他执行此测试的方法,但是它们不适用于许多不同种类的输入。正如Kabie指出的那样,您可以使用集合解决此问题...>>> set(['a', 'b']).issubset(set(['a', 'b', 'foo', 'bar']))True>>> {'a', 'b'} <= {'a', 'b', 'foo', 'bar'}True...有时:>>> {'a', ['b']} <= {'a', ['b'], 'foo', 'bar'}Traceback (most recent call last): File "", line 1, in TypeError: unhashable type: 'list'只能使用可哈希元素创建集。但是生成器表达式all(x in container for x in items)几乎可以处理任何容器类型。唯一的要求是container可重复使用(即不是生成器)。items可以是任何可迭代的。>>> container = [['b'], 'a', 'foo', 'bar']>>> items = (i for i in ('a', ['b']))>>> all(x in [['b'], 'a', 'foo', 'bar'] for x in items)True速度测试在许多情况下,子集测试会比快all,但差异并不令人震惊-除非问题无关紧要,因为集不是一个选择,除非。仅将列表转换为集合是为了进行这样的测试并不总是值得为此感到麻烦。而且,将生成器转换为集合有时会非常浪费,将程序减慢了多个数量级。这里有一些基准用于说明。最大的区别来当两个container和items都比较小。在这种情况下,子集方法要快一个数量级:>>> smallset = set(range(10))>>> smallsubset = set(range(5))>>> %timeit smallset >= smallsubset110 ns ± 0.702 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)>>> %timeit all(x in smallset for x in smallsubset)951 ns ± 11.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)这看起来有很大的不同。但是,只要container有一套,all就可以在更大的规模上完美使用:>>> bigset = set(range(100000))>>> bigsubset = set(range(50000))>>> %timeit bigset >= bigsubset1.14 ms ± 13.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)>>> %timeit all(x in bigset for x in bigsubset)5.96 ms ± 37 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)使用子集测试仍然更快,但在这种规模下仅提高了约5倍。速度的提高归功于Python的快速c支持的实现set,但是两种情况下的基本算法都是相同的。如果items由于其他原因已经将您的信息存储在列表中,那么在使用子集测试方法之前,您必须将它们转换为集合。然后加速降到大约2.5倍:>>> %timeit bigset >= set(bigsubseq)2.1 ms ± 49.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)如果您container是一个序列,并且需要先进行转换,那么加速会更小:>>> %timeit set(bigseq) >= set(bigsubseq)4.36 ms ± 31.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)我们唯一灾难性地得到缓慢结果的时间是当我们container按顺序离开时:>>> %timeit all(x in bigseq for x in bigsubseq)184 ms ± 994 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)当然,只有在必须的情况下,我们才会这样做。如果其中的所有项目bigseq都是可哈希的,那么我们将改为:>>> %timeit bigset = set(bigseq); all(x in bigset for x in bigsubseq)7.24 ms ± 78 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)这仅比替代方法(set(bigseq) >= set(bigsubseq),位于4.36处的时间)快1.66倍。因此,子集测试通常更快,但幅度并不惊人。另一方面,让我们看看何时all更快。如果items一千万个值长,并且可能具有不包含的值container怎么办?>>> %timeit hugeiter = (x * 10 for bss in [bigsubseq] * 2000 for x in bss); set(bigset) >= set(hugeiter)13.1 s ± 167 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)>>> %timeit hugeiter = (x * 10 for bss in [bigsubseq] * 2000 for x in bss); all(x in bigset for x in hugeiter)2.33 ms ± 65.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)在这种情况下,将发电机转换为发电机组非常浪费。该set构造具有消耗整个发电机。但是的短路行为all确保了仅消耗一小部分发电机,因此它比子集测试快四个数量级。诚然,这是一个极端的例子。但正如它显示的那样,您不能假设一种方法或另一种方法在所有情况下都更快。结果在大多数情况下container,至少当其所有元素都可哈希化时,转换为集合才是值得的。这是因为infor集为O(1),而insequence为O(n)。另一方面,有时仅值得使用子集测试。如果您的测试项目已经存储在集中,则绝对可以这样做。否则,all只会慢一点,并且不需要任何其他存储。它也可以与大型项目生成器一起使用,在这种情况下有时可以大大提高速度。