<blockquote>
<h3>How do I check if something is (not) in a list in Python?</h3>
</blockquote>
<p>最便宜、最可读的解决方案是使用<a href="https://docs.python.org/3/reference/expressions.html#membership-test-operations" rel="noreferrer">^{<cd1>}</a>运算符(或者在您的特定情况下,使用<code>not in</code>)。如文件所述</p>
<blockquote>
<p>The operators <code>in</code> and <code>not in</code> test for membership. <code>x in s</code> evaluates to
<code>True</code> if <code>x</code> is a member of <code>s</code>, and <code>False</code> otherwise. <code>x not in s</code> returns
the negation of <code>x in s</code>.</p>
</blockquote>
<p>另外</p>
<blockquote>
<p>The operator <code>not in</code> is defined to have the inverse true value of <code>in</code>.</p>
</blockquote>
<p><code>y not in x</code>在逻辑上与<code>not y in x</code>相同。</p>
<p>下面是几个例子:</p>
<pre><code>'a' in [1, 2, 3]
# False
'c' in ['a', 'b', 'c']
# True
'a' not in [1, 2, 3]
# True
'c' not in ['a', 'b', 'c']
# False
</code></pre>
<p>这也适用于元组,因为元组是散列的(因为它们也是不可变的):</p>
<pre><code>(1, 2) in [(3, 4), (1, 2)]
# True
</code></pre>
<p>如果RHS上的对象定义了<a href="https://docs.python.org/3/reference/datamodel.html#object.__contains__" rel="noreferrer">^{<cd5>}</a>方法,<code>in</code>将在内部调用它,如文档<a href="https://docs.python.org/3/library/stdtypes.html?highlight=__contains__#comparisons" rel="noreferrer">Comparisons</a>部分最后一段所述。</p>
<blockquote>
<p>... <code>in</code> and <code>not in</code>,
are supported by types that are iterable or implement the
<code>__contains__()</code> method. For example, you could (but shouldn't) do this:</p>
</blockquote>
<pre><code>[3, 2, 1].__contains__(1)
# True
</code></pre>
<p><code>in</code>短路,因此如果元素位于列表的开头,<code>in</code>计算速度更快:</p>
<pre><code>lst = list(range(10001))
%timeit 1 in lst
%timeit 10000 in lst # Expected to take longer time.
68.9 ns ± 0.613 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
178 µs ± 5.01 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
</code></pre>
<p>如果您想做的不仅仅是检查列表中是否有项目,还可以选择:</p>
<ul>
<li><code>list.index</code>可用于检索项的索引。如果该元素不存在,则引发<code>ValueError</code>。</li>
<li><code>list.count</code>如果要计算出现次数,可以使用。</li>
</ul>
<hr/>
<h3>XY问题:你考虑过<code>set</code>s吗?</h3>
<p>问自己以下问题:</p>
<ul>
<li>你需要不止一次检查一个项目是否在列表中?</li>
<li>这个检查是在循环内完成的,还是在重复调用函数时完成的?</li>
<li>你在列表中存储的项目是散列的吗?你能打电话给他们吗?</li>
</ul>
<p>如果您对这些问题的回答是“是”,则应该使用<code>set</code>。对<code>list</code>s的<code>in</code>成员资格测试是O(n)时间复杂度。这意味着python必须对列表进行线性扫描,访问每个元素并将其与搜索项进行比较。如果重复执行此操作,或者如果列表很大,则此操作将产生开销。</p>
<p><code>set</code>另一方面,对象散列它们的值以进行常量时间成员身份检查。检查也使用<code>in</code>完成:</p>
<pre><code>1 in {1, 2, 3}
# True
'a' not in {'a', 'b', 'c'}
# False
(1, 2) in {('a', 'c'), (1, 2)}
# True
</code></pre>
<p>如果不幸的是,您正在搜索/未搜索的元素位于列表的末尾,python将一直扫描到列表的末尾。从下面的计时可以明显看出这一点:</p>
<pre><code>l = list(range(100001))
s = set(l)
%timeit 100000 in l
%timeit 100000 in s
2.58 ms ± 58.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
101 ns ± 9.53 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
</code></pre>
<p>提醒一下,只要您正在存储和查找的元素是散列的,那么这是一个合适的选项。总之,它们要么是不可变的类型,要么是实现<code>__hash__</code>的对象。</p>