为什么“如果不是someobj:”比Python中的“if someobj == None:”更好?

我已经看到了几个这样的代码的例子:

if not someobj: #do something 

但我想知道为什么不这样做:

 if someobj == None: #do something 

有什么区别吗? 一个人比另一个人有优势吗?

在第一个testing中,Python尝试将对象转换为一个bool值,如果它不是一个。 粗略地说, 我们在问这个对象:你有意思吗? 这是使用以下algorithm完成的:

  1. 如果对象有一个__nonzero__特殊方法(就像数字内置的intfloat ),它会调用这个方法。 它必须返回一个直接使用的bool值,或者返回一个如果等于零则认为是Falseint值。

  2. 否则,如果对象有一个__len__特殊方法(就像容器的内置函数, listdictsettuple等一样),它会调用这个方法,如果容器是空的(长度为零)则考虑容器False

  3. 否则,该对象被认为是True除非它是None在这种情况下,它被认为是False

在第二个testing中,对象被比较为None 。 在这里, 我们在问这个对象:“你是否等于这个其他的价值?” 这是使用以下algorithm完成的:

  1. 如果该对象有一个__eq__方法,则调用该方法,然后将返回值转换为bool值,并用于确定if的结果。

  2. 否则,如果该对象有一个__cmp__方法,则调用该方法。 这个函数必须返回一个int值来表示两个对象的顺序(如果self < other ,则返回-1 ,如果self == other则返回0 ,如果self > other +1

  3. 否则,对象的身份进行比较(即它们是参考相同的对象,可以由is运算符testing)。

使用is运算符还有另一个可能的testing。 我们会问这个对象:“你是这个特定对象吗?”

一般来说,我build议使用非数值的第一个testing,当你想比较相同的性质(两个string,两个数字,…)的对象时,使用testing相等,只有当使用sentinel值( None意味着没有初始化成员字段为例,或者当使用getattr__getitem__方法)。

总结一下,我们有:

 >>> class A(object): ... def __repr__(self): ... return 'A()' ... def __nonzero__(self): ... return False >>> class B(object): ... def __repr__(self): ... return 'B()' ... def __len__(self): ... return 0 >>> class C(object): ... def __repr__(self): ... return 'C()' ... def __cmp__(self, other): ... return 0 >>> class D(object): ... def __repr__(self): ... return 'D()' ... def __eq__(self, other): ... return True >>> for obj in ['', (), [], {}, 0, 0., A(), B(), C(), D(), None]: ... print '%4s: bool(obj) -> %5s, obj == None -> %5s, obj is None -> %5s' % \ ... (repr(obj), bool(obj), obj == None, obj is None) '': bool(obj) -> False, obj == None -> False, obj is None -> False (): bool(obj) -> False, obj == None -> False, obj is None -> False []: bool(obj) -> False, obj == None -> False, obj is None -> False {}: bool(obj) -> False, obj == None -> False, obj is None -> False 0: bool(obj) -> False, obj == None -> False, obj is None -> False 0.0: bool(obj) -> False, obj == None -> False, obj is None -> False A(): bool(obj) -> False, obj == None -> False, obj is None -> False B(): bool(obj) -> False, obj == None -> False, obj is None -> False C(): bool(obj) -> True, obj == None -> True, obj is None -> False D(): bool(obj) -> True, obj == None -> True, obj is None -> False None: bool(obj) -> False, obj == None -> True, obj is None -> True 

这些实际上都是不好的做法。 曾几何时,认为随便把“无”和“假”视为相似。 但是,由于Python 2.2这不是最好的策略。

首先,当你做一个if x或者if not xtypes的testing时,Python必须隐含地把x转换为布尔值。 bool函数的规则描述了一系列错误的东西; 一切都是真的。 如果x的值不适合布尔值,那么这种隐式转换并不是说明事情的最明确方式。

在Python 2.2之前,没有bool函数,所以更不清楚。

其次,你不应该用== Nonetesting。 你应该使用“ is Noneis not None

请参阅PEP 8, Python代码样式指南 。

 - Comparisons to singletons like None should always be done with 'is' or 'is not', never the equality operators. Also, beware of writing "if x" when you really mean "if x is not None" -- eg when testing whether a variable or argument that defaults to None was set to some other value. The other value might have a type (such as a container) that could be false in a boolean context! 

那里有几个单身人士? 五: NoneTrueFalseNoneEllipsis 。 既然你不太可能使用NotImplemented或者Ellipsis ,并且你永远不会说if x is True (因为if x更清晰的话),你将只能testingNone

因为None不是唯一被认为是错误的。

 if not False: print "False is false." if not 0: print "0 is false." if not []: print "An empty list is false." if not (): print "An empty tuple is false." if not {}: print "An empty dict is false." if not "": print "An empty string is false." 

False0()[]{}""都与None不同,所以你的两个代码片段是相同的。

此外,请考虑以下几点:

 >>> False == 0 True >>> False == () False 

if object: 不是一个相等性检查。 0()[]None{}都是不同的,但都是False。

这是短路expression式背后的“魔术”,例如:

 foo = bar and spam or eggs 

这是简写​​为:

 if bar: foo = spam else: foo = eggs 

虽然你真的应该写:

 foo = spam if bar else egg 

如果你问

 if not spam: print "Sorry. No SPAM." 

垃圾邮件__nonzero__方法被调用。 从Python手册:

__nonzero__self )被调用来实现真值testing,并且内置操作bool(); 应该返回False或者True,或者等于0或者1的整数。当这个方法没有被定义的时候,__len __()被调用,如果被定义的话(见下面)。 如果一个类既没有定义__len __()也没有定义__nonzero __(),所有的实例都被认为是真的。

如果你问

 if spam == None: print "Sorry. No SPAM here either." 

用参数None调用垃圾邮件__eq__方法。

有关定制可能性的更多信息,请参阅https://docs.python.org/reference/datamodel.html#basic-customization中的Python文档;

PEP 8 – Python代码样式指南build议使用否,如果您正在testingNone-ness

 - Comparisons to singletons like None should always be done with 'is' or 'is not', never the equality operators. 

另一方面,如果您testing的不是无关性,则应使用布尔运算符。

这两个比较服务于不同的目的。 前者检查布尔值的东西,第二个检查与None值的身份。

对于第一个例子是更短,看起来更好。 根据其他职位你select还取决于你真正想要做的比较。

答案是“这取决于”。

我使用第一个例子,如果我认为0,“”,[]和False(列表不详)在这种情况下等价于None。

就个人而言,我select了跨语言的一致方法: if (var) (或等效)只有当var被声明为布尔值时(或者定义为C,我们没有特定的types)。 我甚至在b加上这些variables(所以它实际上是bVar ),以确保我不会在这里意外地使用另一种types。
我不太喜欢隐式转换为布尔值,更不用说当有许多复杂的规则时。

当然,人们会不同意。 有些更进一步,我在我的工作中看到Java代码中的if (bVar == true) (对于我的口味来说太冗余了!),另外一些人喜欢太紧凑的语法, while (line = getNextLine()) (对我来说太模糊)。