我看过几个像这样的代码示例:
if not someobj:
#do something
但我想知道为什么不这样做:
if someobj == None:
#do something
有区别吗?它们之间有优劣之分吗?
我看过几个像这样的代码示例:
if not someobj:
#do something
但我想知道为什么不这样做:
if someobj == None:
#do something
有区别吗?它们之间有优劣之分吗?
在第一个测试中,如果对象不是bool
值,则Python尝试将对象转换为bool
值。大致上,我们在问对象:你是否有意义?这是使用以下算法完成的:
如果对象具有__nonzero__
特殊方法(如数字内置型int
和float
),则调用此方法。它必须返回一个bool
值,该值直接使用,或者返回一个int
值,如果为零,则被视为False
。
否则,如果对象具有__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
运算符进行另一个测试。我们将问对象:"你是否是这个特定的对象?"
通常建议在非数值类型的情况下使用第一个测试,在需要比较相同类型对象(如两个字符串、两个数字等)时使用相等测试,只有在使用哨兵值(例如表示成员字段未初始化的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值;其他所有值均为True。 如果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
PEP 8 -- Python代码风格指南建议在测试是否为None时使用is或is not
- Comparisons to singletons like None should always be done with
'is' or 'is not', never the equality operators.
另一方面,如果你要测试的不仅是空值,你应该使用布尔运算符。
if not spam:
print "Sorry. No SPAM."
< p >调用spam 的__nonzero__方法,这是来自Python手册的说明:
__nonzero__(self) 被用于实现真值测试和内置操作bool()。应该返回False或True,或它们的整数等价物0或1。当未定义此方法时,如果定义了__len__()(见下文),则调用该方法。如果一个类既不定义__len__()也不定义__nonzero__(),则其所有实例都被视为True。
如果你询问:
if spam == None:
print "Sorry. No SPAM here either."
spam的__eq__方法会被调用,传入参数None。
如需了解更多自定义可能性,请参阅Python文档:https://docs.python.org/reference/datamodel.html#basic-customization
这两种比较有不同的目的。前者检查某个东西的布尔值,而后者检查它是否与None值相同。
首先,第一个示例更短,看起来更好。根据其他帖子所述,您选择的方式也取决于您想要使用比较做什么。
if(var)
(或等效语句)。我甚至会在这些变量前加上一个b前缀(实际上应该是bVar
),以确保我不会意外地在此处使用其他类型。当然,人们会有不同的看法。有些人会更进一步,我在我的工作中看到Java代码中的if(bVar == true)
(对我来说过于冗余!),而其他人则过于喜欢紧凑的语法,如while(line = getNextLine())
(对我来说过于模糊)。
X != None
呢? - Charlie Parker