在 Python 中,为什么“ if not somobj:”比“ if somobj = = Nothing:”好?

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

if not someobj:
#do something

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

if someobj == None:
#do something

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

106958 次浏览

在第一个测试中,如果对象还不是 bool值,Python 会尝试将其转换为 bool值。大致来说,我们问的是对象: 你是否有意义?这是使用以下算法完成的:

  1. 如果对象具有 __nonzero__特殊方法(如数值内置的 intfloat) ,则调用此方法。它必须返回一个 bool值(然后直接使用) ,或者返回一个 int值(如果等于零,则认为是 False)。

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

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

在第二个测试中,将对象与 None进行相等性比较。这里,我们问这个对象,“你等于这个其他值吗?”这是使用以下算法完成的:

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

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

  3. 否则,将对象进行身份比较(即。它们是对同一个对象的引用,可以由 is操作符进行测试)。

还可以使用 is操作符进行另一个测试

一般来说,我建议使用非数值的第一个测试,当你想要比较相同性质的对象(两个字符串,两个数字,...)时使用相等性测试,并且只在使用前哨值时检查身份(例如,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

因为 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。

这就是短路表达式背后的“魔力”,比如:

foo = bar and spam or eggs

简称:

if bar:
foo = spam
else:
foo = eggs

尽管你真的应该写:

foo = spam if bar else egg

这两种比较有不同的目的。前者检查某事物的布尔值,后者检查其标识为 Nothing 值。

第一个例子更短,看起来更好。根据其他帖子,你选择什么也取决于你真正想做的比较。

PEP 8—— Python 代码的样式指南 如果您正在测试 Nothing-ness,建议使用 强大不是

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

另一方面,如果您正在测试的内容超过 Nothing-ness,则应该使用布尔运算符。

答案是“视情况而定”。

如果我认为0、“”、[]和 False (列表并非详尽无遗)等价于此上下文中的 Nothing,则使用第一个示例。

就个人而言,我选择了一种跨语言的一致方法: 只有当 var 声明为 boolean (或定义为 boolean,在 C 语言中我们没有特定的类型)时,我才使用 if (var)(或等效)。我甚至在这些变量前面加了一个 b(实际上应该是 bVar) ,以确保不会意外地在这里使用另一种类型。
我真的不喜欢布尔型的隐式转换,当有许多复杂的规则时更是如此。

当然,人们不会同意。更进一步,我在我的工作中看到了 Java 代码中的 if (bVar == true)(对我来说太多余了!),其他人喜欢太多紧凑的语法,去 while (line = getNextLine())(对我来说太模棱两可)。

实际上,这两种做法都很糟糕。曾几何时,人们认为把“无”和“假”当作类似的东西来随意对待是可以的。但是,由于 Python 2.2,这不是最好的策略。

首先,当您执行 if xif not x类型的测试时,Python 必须隐式地将 x转换为布尔值。bool函数的规则描述了一系列错误的事情,其他的都是真的。如果 x 的值一开始就不是正确的布尔值,那么这种隐式转换就不是最清晰的表达方式。

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

其次,您不应该真正使用 == None进行测试,而应该使用 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"
-- e.g. 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!

有多少个单身人士?五: NoneTrueFalseNotImplementedEllipsis。因为您实际上不太可能使用 NotImplementedEllipsis,而且您永远不会说 if x is True(因为简单地说 if x更清楚) ,所以您将只测试 None

如果你问的话

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

调用 垃圾邮件非零方法:

_ _ nonzero _ _ (自我) 调用以实现真值测试,并且内置的操作 bool () ; 应该返回 False 或 True,或者它们的整数等价物0或1。如果未定义此方法,则调用 _ _ len _ _ ()(如果已定义)。如果一个类既没有定义 _ _ len _ _ ()也没有定义 _ _ nonzero _ _ () ,那么它的所有实例都被认为是 true。

如果你问的话

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

使用参数 没有调用 垃圾邮件好吧方法。

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