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

10 浏览
0 Comments

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

我看到过几个这样的代码示例:

if not someobj:
    #做某事

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

if someobj == None:
    #做某事

有什么区别吗?其中一个有优势吗?

0
0 Comments

为什么在Python中使用"if not someobj:"比"if someobj == None:"更好?

因为None并不是唯一被视为False的对象。

False, 0, (), [], {} 和 "" 都不同于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

关于你的最后一个问题,它们是等价的。

而且两者都是错误的,因为""是False。第二个应该写成 '("",) or ("s",)'。无论如何,现代版本的Python已经有了正确的三元运算符。这种容易出错的技巧应该被淘汰。

0
0 Comments

为什么在Python中,使用"if not someobj:"比"if someobj == None:"更好?

在Python中,这两种写法实际上都是不好的实践。过去,将None和False视为相似的方式被认为是可以接受的。然而,自从Python 2.2版本开始,这已不再是最佳策略。

首先,当你进行if xif not x这样的测试时,Python必须隐式地将x转换为布尔值。对于bool函数的规则描述了一系列为False的情况;其他所有情况均为True。如果x的值一开始就不是合适的布尔值,这种隐式转换并不是最清晰的表达方式。

在Python 2.2之前,甚至没有bool函数,所以更加不清晰。

其次,你不应该使用== None来进行测试。你应该使用is Noneis not None

参见PEP 8,Python代码风格指南。

- 对于单例(singleton)如None的比较,应该始终使用'is'或'is not',而不是等号操作符。
  同时,当你真正想要判断一个默认值为None的变量或参数是否被设置为其他值时,要小心不要写成"if x",而应该写成"if x is not None"。
  -- 例如,当测试一个变量或参数的默认值是否被设置为其他值时,其他值可能具有在布尔环境中为False的类型(例如容器)!

有多少个单例存在?有五个:NoneTrueFalseNotImplementedEllipsis。由于你几乎不太可能使用NotImplementedEllipsis,并且你永远不会写if x is True(因为简单地写if x更清晰明了),你只会测试None

第二种写法绝对不是不好的实践。PEP 8建议使用if x两次。首先用于序列(而不是使用len),然后用于True和False(而不是使用is)。我所见过的几乎所有Python代码都使用了if x和if not x。

0
0 Comments

在Python中,使用"if not someobj:"比"if someobj == None:"更好的原因是,前者会自动调用对象的特殊方法来判断对象是否有意义,而后者只是简单地比较对象是否等于None。

在第一个测试中,如果对象不是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

尽管技术上是正确的,但这并没有解释元组、列表、字典、字符串、Unicode、整数、浮点数等都具有nonzero方法。更常见的是依赖内置类型的真值,而不是依赖自定义的nonzero方法。

0