为什么在Python中“如果不是someobj:”比“if someobj == None:”更好?
我已经看到了几个这样的代码的例子:
if not someobj:
#do something
但我想知道为什么不这样做:
if someobj == None:
#do something
有什么区别吗? 一个人比另一个人有优势吗?
在第一个测试中,Python尝试将对象转换为一个bool
值,如果它不是一个。 粗略地说, 我们在问这个对象:你是否有意义? 这是使用以下算法完成的:
如果对象有一个__nonzero__
特殊方法(就像数字内置, int
和float
),它会调用这个方法。 它必须返回一个直接使用的bool
值,或者返回一个如果等于零则认为是False
的int
值。
否则,如果对象有一个__len__
特殊方法(就像容器内置函数, list
, dict
, set
, tuple
等一样),它会调用这个方法,如果容器为空(长度为零)则考虑容器False
。
否则,该对象被认为是True
除非它是None
在这种情况下,它被认为是False
。
在第二个测试中,对象与None
进行比较。 在这里, 我们问这个对象,“你是否等于这个其他的价值?” 这是使用以下算法完成的:
如果该对象有一个__eq__
方法,则调用该方法,然后将返回值转换为bool
值并用于确定if
的结果。
否则,如果该对象具有__cmp__
方法,则会调用该方法。 这个函数必须返回一个int
值来表示两个对象的顺序(如果self < other
,则为-1
,如果self == other
则为0
,如果self > other
+1
)。
否则,对象的身份进行比较(即它们引用的是同一个对象,可以由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
这些实际上都是不好的做法。 曾几何时,认为随便把None和False视为相似是可以的。 但是,从Python 2.2开始,这不是最好的策略。
首先,当你做一个if x
或者if not x
类型的测试时,Python必须将x
隐式转换为布尔值。 bool
函数的规则描述了大量的False事件; 其他一切都是真的。 如果x的值不适合布尔值,那么这种隐式转换并不是说明事情的最明确方式。
在Python 2.2之前,没有bool函数,所以它更不清楚。
其次,你不应该用== None
测试。 您应该使用“ is None
并且is 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!
有多少个单身人士? 五: None
, True
, False
, NotImplemented
和Ellipsis
。 既然你不太可能使用NotImplemented
或者Ellipsis
,并且你永远不会说if x is True
(因为if x
更清晰),你将只能测试None
。
因为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."
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
链接地址: http://www.djcxy.com/p/31685.html
上一篇: Why is "if not someobj:" better than "if someobj == None:" in Python?