在测试成员资格时,我们可以使用:
x not in y
或者,另一种选择是:not x in y
根据 x
和 y
的不同,这个表达式可能有许多可能的语境。例如,它可以用于子字符串检查、列表成员资格、字典键存在性等。
- 这两种形式总是等效的吗?
- 是否有优选语法?
它们总是给出相同的结果。
事实上,not 'ham' in 'spam and eggs'
被特殊处理为执行单个的 "not in" 操作,而不是执行 "in" 操作并取反结果:
>>> import dis
>>> def notin():
'ham' not in 'spam and eggs'
>>> dis.dis(notin)
2 0 LOAD_CONST 1 ('ham')
3 LOAD_CONST 2 ('spam and eggs')
6 COMPARE_OP 7 (not in)
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
>>> def not_in():
not 'ham' in 'spam and eggs'
>>> dis.dis(not_in)
2 0 LOAD_CONST 1 ('ham')
3 LOAD_CONST 2 ('spam and eggs')
6 COMPARE_OP 7 (not in)
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
>>> def not__in():
not ('ham' in 'spam and eggs')
>>> dis.dis(not__in)
2 0 LOAD_CONST 1 ('ham')
3 LOAD_CONST 2 ('spam and eggs')
6 COMPARE_OP 7 (not in)
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
>>> def noteq():
not 'ham' == 'spam and eggs'
>>> dis.dis(noteq)
2 0 LOAD_CONST 1 ('ham')
3 LOAD_CONST 2 ('spam and eggs')
6 COMPARE_OP 2 (==)
9 UNARY_NOT
10 POP_TOP
11 LOAD_CONST 0 (None)
14 RETURN_VALUE
一开始我以为它们总是给出相同的结果,但是not
本身只是一个优先级较低的逻辑取反运算符,可以像任何其他布尔表达式一样应用于a in b
,而not in
则是一种方便和清晰的分离运算符。
上面的反汇编结果很有启示性!看起来,虽然not
显然是一个逻辑取反运算符,但形式not a in b
是特殊情况,因此它实际上并没有使用通用运算符。这使得not a in b
字面上与a not in b
相同,而不仅仅是产生相同值的表达式。
not in
操作符:
另请参见"PythonE713: 成员测试应该使用
not in
if x is not None
or if not x is None
?",这是一个非常类似的风格选择。其他人已经非常清楚地表明这两个语句,在很低的水平上是等价的。
然而,我认为还没有任何人强调过,既然这样留下了选择的余地,你应该选择让你的代码尽可能容易阅读的形式。
并不一定要尽可能容易阅读对于任何人,即使这当然是一个很好的目标。相反,确保代码尽可能容易阅读对于你自己,因为你最有可能回来查看这段代码并尝试阅读它。
在Python中,没有差别。也没有偏好。
从语法上讲,它们是相同的语句。我会很快地说'ham' not in 'spam and eggs'
传达了更清晰的意图,但我见过代码和情境,其中not 'ham' in 'spam and eggs'
比另一个传达了更清晰的含义。
not x in xs
,即not (x in xs)
。但是它被解析成与x not in xs
完全相同的字节码实现的事实非常清楚地表明它们必须始终相同,而不像not x == y
vsx != y
这样的东西应该给出相同的结果,但不一定(取决于涉及的__eq__
和__ne__
的实现)。 - Ben