Python“如果x不是无”或“如果不是x是无”?

我一直认为if not x is None版本更清晰,但是谷歌的风格指南PEP-8都使用if x is not None。是否有任何轻微的性能差异(我假设没有),是否有任何情况下一个真的不合适(使另一个成为我的惯例的明显赢家)?*

*我指的是任何单例,而不仅仅是None

…来比较像无。使用是或不是。

1254036 次浏览

Google和python的风格指南都是最佳实践:

if x is not None:# Do something about x

使用not x可能会导致不需要的结果。

见下图:

>>> x = 1>>> not xFalse>>> x = [1]>>> not xFalse>>> x = 0>>> not xTrue>>> x = [0]         # You don't want to fall in this one.>>> not xFalse

您可能有兴趣了解Python中哪些文字被评估为TrueFalse


在下面编辑评论:

我只是做了更多的测试。not x is None不会先否定x,然后再与None进行比较。事实上,当以这种方式使用时,is运算符似乎具有更高的优先级:

>>> x[0]>>> not x is NoneTrue>>> not (x is None)True>>> (not x) is NoneFalse

因此,在我看来,not x is None是最好避免的。


更多编辑:

我刚刚做了更多测试,可以确认bukzor的评论是正确的。(至少,我无法证明它是正确的。)

这意味着if x is not Noneif not x is None的结果相同。我接受纠正。谢谢bukzor。

然而,我的答案仍然存在:使用常规#0

if not x is None与其他编程语言更相似,但if x is not None对我来说听起来更清晰(并且在英语中语法更正确)。

也就是说,这对我来说似乎更像是一种偏好。

代码应该首先写成程序员可以理解的,其次是编译器或解释器。“is not”构造比“not is”更像英语。

没有性能差异,因为它们编译为相同的字节码:

>>> import dis>>> dis.dis("not x is None")1           0 LOAD_NAME                0 (x)2 LOAD_CONST               0 (None)4 COMPARE_OP               9 (is not)6 RETURN_VALUE>>> dis.dis("x is not None")1           0 LOAD_NAME                0 (x)2 LOAD_CONST               0 (None)4 COMPARE_OP               9 (is not)6 RETURN_VALUE

在文体上,我尽量避免not x is y,人类读者可能会把它误解为(not x) is y。如果我写x is not y,那么就没有歧义了。

由于文体原因,is not运算符优于否定is的结果。“if x is not None:”读起来像英语,但“if not x is None:”需要理解运算符的优先级,读起来不像英语。

如果有性能差异,我的钱在is not上,但这几乎肯定不是决定更喜欢该技术的动机。这显然是依赖于实现的。由于is不可覆盖,无论如何,优化任何区别都应该很容易。

答案比人们想的要简单。

无论哪种方式都没有技术优势,而“x不是y”是其他人都用,这使它成为明显的赢家。它“看起来更像英语”与否并不重要;每个人都使用它,这意味着每个Python用户——甚至是中国用户,他们的语言看起来一点也不像Python——都会一眼就理解它,而稍微不那么常见的语法需要几个额外的大脑周期来解析。

不要为了与众不同而与众不同,至少在这个领域是这样的。

Pythonif x is not None还是if not x is None

TLDR:字节码编译器将它们都解析为x is not None-因此为了易读性,请使用if x is not None

可读性

我们使用Python是因为我们重视人类的易读性、可用性和各种编程范式的正确性而不是性能。

Python优化了易读性,尤其是在这种情况下。

解析和编译字节码

not结合更弱is,所以这里没有逻辑上的区别。参见留档

运算符isis not测试对象身份:x is y为true当且仅当x和y是同一个对象。x is not y产生逆真值。

is not在Python语法中特别提供,作为语言的易读性改进:

comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not'

所以它也是语法的一个统一元素。

当然,它的解析不一样:

>>> import ast>>> ast.dump(ast.parse('x is not None').body[0].value)"Compare(left=Name(id='x', ctx=Load()), ops=[IsNot()], comparators=[Name(id='None', ctx=Load())])">>> ast.dump(ast.parse('not x is None').body[0].value)"UnaryOp(op=Not(), operand=Compare(left=Name(id='x', ctx=Load()), ops=[Is()], comparators=[Name(id='None', ctx=Load())]))"

但是字节编译器实际上会将not ... is转换为is not

>>> import dis>>> dis.dis(lambda x, y: x is not y)1           0 LOAD_FAST                0 (x)3 LOAD_FAST                1 (y)6 COMPARE_OP               9 (is not)9 RETURN_VALUE>>> dis.dis(lambda x, y: not x is y)1           0 LOAD_FAST                0 (x)3 LOAD_FAST                1 (y)6 COMPARE_OP               9 (is not)9 RETURN_VALUE

因此,为了易读性和使用预期的语言,请使用is not

不要使用它不是明智。

我更喜欢更可读的形式x is not y比我想象的最终如何编写运算符的代码处理优先级,以产生更具可读性的代码。

就我个人而言,我使用

if not (x is None):

每个程序员都可以毫不含糊地立即理解,即使是那些不熟悉Python语法的程序员。