为什么在Python中“if not someobj:”比“if someobj==None:”更好?

2024-03-29 05:07:45 发布

您现在位置:Python中文网/ 问答频道 /正文

我见过这样的代码示例:

if not someobj:
    #do something

但我想知道为什么不:

if someobj == None:
    #do something

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


Tags: 代码none示例ifnotdosomething区别
3条回答

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

在第一个测试中,Python尝试将对象转换为一个bool值(如果它还不是一个值)。粗略地说,我们问的是:你有没有意义?这是使用以下算法完成的:

  1. 如果对象有一个__nonzero__特殊方法(就像数字内置的intfloat),它将调用此方法。它必须返回一个随后直接使用的bool值,或者如果等于零,则返回一个被视为int值。

  2. 否则,如果对象有一个__len__特殊方法(容器内置的listdictsettuple,…),则调用此方法,如果该方法为空(长度为零),则考虑容器False

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

在第二个测试中,比较对象是否与None相等。在这里,我们问这个对象,“你是否等于另一个值?”这是使用以下算法完成的:

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

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

  3. 否则,将比较对象的标识(即它们是对同一对象的引用,可以通过is运算符进行测试)。

可以使用is运算符进行另一个测试。我们会问对象,“你是这个特定对象吗?”

一般来说,我建议对非数值使用第一个测试,当您要比较相同性质的对象(两个字符串、两个数字,…)时使用相等测试,并且仅当使用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

这实际上都是不好的做法。曾几何时,人们认为随便地把“无”和“假”当作相似的东西是可以的。但是,由于Python2.2,这不是最好的策略。

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

在Python2.2之前,没有bool函数,所以它就更不清晰了。

第二,您不应该真正使用== None进行测试。您应该使用is Noneis not None

见政治公众人物8,Style Guide for Python Code

- 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

相关问题 更多 >