x不在" 与 "不在x中
我注意到这两种写法效果是一样的:
if x not in list
和 if not x in list
。
这两种写法在某些情况下有什么区别吗?为什么会有这两种写法,难道只是因为有些人觉得其中一种写起来更顺手吗?
我在别人写的代码中更可能看到哪一种呢?
5 个回答
not x in L
这个写法并没有被明确禁止,因为这样做没什么意义。x not in L
这个写法是被允许的(虽然它们编译成的字节码是一样的),因为这样看起来更容易理解。
不过,大家通常都是用 x not in L
这个写法。
>>> dis.dis(lambda: a not in b)
1 0 LOAD_GLOBAL 0 (a)
3 LOAD_GLOBAL 1 (b)
6 COMPARE_OP 7 (not in)
9 RETURN_VALUE
>>> dis.dis(lambda: not a in b)
1 0 LOAD_GLOBAL 0 (a)
3 LOAD_GLOBAL 1 (b)
6 COMPARE_OP 7 (not in)
9 RETURN_VALUE
当你写“not a in b”时,它需要转换成“(not in)”的形式。
所以,正确的写法是“a not in b”。
这两种写法生成的字节码是完全一样的,你可以很清楚地验证这一点:
>>> import dis
>>> dis.dis(compile('if x not in d: pass', '', 'exec'))
1 0 LOAD_NAME 0 (x)
3 LOAD_NAME 1 (d)
6 COMPARE_OP 7 (not in)
9 JUMP_IF_FALSE 4 (to 16)
12 POP_TOP
13 JUMP_FORWARD 1 (to 17)
>> 16 POP_TOP
>> 17 LOAD_CONST 0 (None)
20 RETURN_VALUE
>>> dis.dis(compile('if not x in d: pass', '', 'exec'))
1 0 LOAD_NAME 0 (x)
3 LOAD_NAME 1 (d)
6 COMPARE_OP 7 (not in)
9 JUMP_IF_FALSE 4 (to 16)
12 POP_TOP
13 JUMP_FORWARD 1 (to 17)
>> 16 POP_TOP
>> 17 LOAD_CONST 0 (None)
20 RETURN_VALUE
所以它们在语义上是相同的。
从风格上讲,PEP 8 并没有提到这个问题。
个人来说,我更喜欢 if x not in y
这种写法——这样一来,not in
就很明显是一个整体操作符,而且 读起来像英语。相比之下,if not x in y
可能会让一些读者误以为它的意思是 if (not x) in y
(也就是把“x”的值反转),读起来不太像英语,而且没有任何好处。
使用 if x not in y
这种写法在有多个条件时,代码的可读性也会更好。例如,考虑这个语句 if not x in y and x in m
。随便看一下的人可能会以为它的意思是 if not (x in y and x in m)
,但实际上代码是 if (not x in y) and (x in m)
,这会让人感到意外。因此,把 not
放在它所属的 in
操作符旁边,可以清楚地表明 not in
只适用于那个特定的条件,而不是所有条件。
因此,if x not in y and x in m
在可读性上有很多好处,不管编程经验如何,理解起来都更简单。此外,not in
是“not in”字节码操作符的官方名称(在上面的反汇编中可以看到),这进一步确认了 not in
是 Python 推荐的写法。
我们再考虑一个类似的语句。就是 is not
条件。如果你试图写 if not x is True
,就会很明显地看到这种写法有多么奇怪和反向。它们在逻辑上都没有意义,但在 is not
的例子中就显得特别明显。
总之,if X is not Y
和 if X not in Y
是编写这类 Python 语句的推荐方式。