关于编码风格:Python`如果x不是None`或`if not x is None`?

Python `if x is not None` or `if not x is None`?

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

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

...to compare singletons like
None. Use is or is not.


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Python 2.6.2 (r262:71600, Apr 15 2009, 07:20:39)
>>> import dis
>>> def f(x):
...    return x is not None
...
>>> dis.dis(f)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               0 (None)
              6 COMPARE_OP               9 (is not)
              9 RETURN_VALUE
>>> def g(x):
...   return not x is None
...
>>> dis.dis(g)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               0 (None)
              6 COMPARE_OP               9 (is not)
              9 RETURN_VALUE

在风格上,我尽量避免使用not x is y。尽管编译器总是将其视为not (x is y),但人类读者可能会误解该构造为(not x) is y。如果我写的是x is not y,那么就没有歧义。


谷歌和Python的风格指南都是最佳实践:

1
2
if x is not None:
    # Do something about x

使用not x会导致不必要的结果。见下文:

1
2
3
4
5
6
7
8
9
10
11
12
>>> x = 1
>>> not x
False
>>> x = [1]
>>> not x
False
>>> x = 0
>>> not x
True
>>> x = [0]         # You don't want to fall in this one.
>>> not x
False

您可能有兴趣了解在python中对TrueFalse的哪些文本进行了评估:

  • 真值检验

编辑以下评论:

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

1
2
3
4
5
6
7
8
>>> x
[0]
>>> not x is None
True
>>> not (x is None)
True
>>> (not x) is None
False

因此,在我看来,以东十一〔三〕是公正的,最好避免。

更多编辑:

我只是做了更多的测试,可以确认Bukzor的评论是正确的。(至少,我无法证明这一点。)

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

然而,我的回答仍然是:使用传统的if x is not None:]


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


答案比人们想象的要简单。

这两种方法都没有技术优势,"x不是y"是其他人都使用的,这使得它成为了一个明确的赢家。不管它是否"看起来更像英语",每个人都会使用它,这意味着Python的每一个用户——甚至中国的用户,他们的语言Python看起来一点也不像——都会一目了然地理解它,在这里,稍微不常见的语法需要几个额外的大脑周期来解析。

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


Python if x is not None or if not x is None?

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

可读性

我们使用python是因为我们重视人的可读性、可用性和各种编程范例的正确性,而不是性能。

python针对可读性进行了优化,特别是在这个上下文中。

解析和编译字节码

not的结合比is弱,因此这里没有逻辑上的区别。请参阅文档:

The operators is and is not test for object identity: x is y is true
if and only if x and y are the same object. x is not y yields the
inverse truth value.

在python语法中,为了提高语言的可读性,专门提供了is not

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

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

当然,它的解析方式不同:

1
2
3
4
5
>>> 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

1
2
3
4
5
6
7
8
9
10
11
>>> 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

不使用它是不明智的。


由于文体原因,与否定is的结果相比,is not运算符更受欢迎。"if x is not None:的读法和英语一样,但"if not x is None:要求理解运算符的优先顺序,而不是像英语那样读。

如果存在性能差异,我的钱就花在EDOCX1上了(18),但这几乎肯定不是决定更喜欢这种技术的动机。它显然依赖于实现。由于is不是可覆盖的,所以无论如何,应该很容易优化出任何区别。


我个人用

1
if not (x is None):

每个程序员,甚至那些不精通Python语法的程序员,都能立即理解它,而不会产生歧义。


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

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


我更喜欢更易读的形式x is not y。我不知道如何最终编写代码处理操作符的优先级,以便生成更可读的代码。


试试这个:

1
2
    if x != None:
       # do stuff with x