我一直认为如果不是x是None版本更清楚,但谷歌的风格指南和PEP-8都使用如果x不是None。是否存在任何微小的性能差异(我假设没有),是否存在其中一个确实不适合的情况(使另一个成为我的大会的明显赢家)?*
*我指的是任何单例,而不仅仅是None。
...比较单身人士喜欢 一个也没有。使用是或不是。
我一直认为如果不是x是None版本更清楚,但谷歌的风格指南和PEP-8都使用如果x不是None。是否存在任何微小的性能差异(我假设没有),是否存在其中一个确实不适合的情况(使另一个成为我的大会的明显赢家)?*
*我指的是任何单例,而不仅仅是None。
...比较单身人士喜欢 一个也没有。使用是或不是。
当前回答
Python如果x不是None或如果不是x是None?
TLDR:字节码编译器将它们都解析为x不是None -因此为了可读性,使用if x不是None。
可读性
我们使用Python是因为我们重视人类的可读性、可用性和各种编程范式的正确性,而不是性能。
Python优化了可读性,特别是在这个上下文中。
解析和编译字节码
not的绑定比is更弱,所以这里没有逻辑上的区别。参见文档:
操作符is和is not测试对象的同一性:x是y是真 当且仅当x和y是同一个对象。X不是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())]))"
但是字节编译器实际上会翻译不是。是不是:
>>> 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。
不使用它是不明智的。
其他回答
答案比人们想象的要简单。
这两种方法都没有技术优势,而且“x不是y”是其他人都用的,这使它成为明显的赢家。它“看起来更像英语”与否并不重要;每个人都使用它,这意味着Python的每个用户——甚至是中国用户,他们的语言Python看起来一点也不像——一眼就能理解它,其中稍微不太常见的语法将需要额外的几个大脑周期来解析。
不要为了与众不同而与众不同,至少在这个领域是这样。
就我个人而言,我使用
if not (x is None):
每个程序员都能立即理解,没有歧义,即使那些不是Python语法专家。
Python如果x不是None或如果不是x是None?
TLDR:字节码编译器将它们都解析为x不是None -因此为了可读性,使用if x不是None。
可读性
我们使用Python是因为我们重视人类的可读性、可用性和各种编程范式的正确性,而不是性能。
Python优化了可读性,特别是在这个上下文中。
解析和编译字节码
not的绑定比is更弱,所以这里没有逻辑上的区别。参见文档:
操作符is和is not测试对象的同一性:x是y是真 当且仅当x和y是同一个对象。X不是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())]))"
但是字节编译器实际上会翻译不是。是不是:
>>> 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。
不使用它是不明智的。
它们没有性能差异,因为它们编译为相同的字节码:
>>> 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
在文体上,我尽量避免“不是x是y”,人类读者可能会误解为“(不是x)是y”。如果我写“x不是y”,那么就没有歧义。
由于风格原因,使用is not运算符比对is的结果求反更可取。"if x is not None:"读起来就像英语,但"if not x is None:"需要理解操作符优先级,读起来不像英语。
如果存在性能差异,我的赌注是没有,但这几乎肯定不是选择这种技术的动机。它显然是依赖于实现的。由于is是不可重写的,因此无论如何都应该很容易优化出任何区别。