为什么“如果不是someobj:”比Python中的“if someobj == None:”更好?
我已经看到了几个这样的代码的例子:
if not someobj: #do something
但我想知道为什么不这样做:
if someobj == None: #do something
有什么区别吗? 一个人比另一个人有优势吗?
在第一个testing中,Python尝试将对象转换为一个bool
值,如果它不是一个。 粗略地说, 我们在问这个对象:你有意思吗? 这是使用以下algorithm完成的:
-
如果对象有一个
__nonzero__
特殊方法(就像数字内置的int
和float
),它会调用这个方法。 它必须返回一个直接使用的bool
值,或者返回一个如果等于零则认为是False
的int
值。 -
否则,如果对象有一个
__len__
特殊方法(就像容器的内置函数,list
,dict
,set
,tuple
等一样),它会调用这个方法,如果容器是空的(长度为零)则考虑容器False
。 -
否则,该对象被认为是
True
除非它是None
在这种情况下,它被认为是False
。
在第二个testing中,对象被比较为None
。 在这里, 我们在问这个对象:“你是否等于这个其他的价值?” 这是使用以下algorithm完成的:
-
如果该对象有一个
__eq__
方法,则调用该方法,然后将返回值转换为bool
值,并用于确定if
的结果。 -
否则,如果该对象有一个
__cmp__
方法,则调用该方法。 这个函数必须返回一个int
值来表示两个对象的顺序(如果self < other
,则返回-1
,如果self == other
则返回0
,如果self > other
+1
。 -
否则,对象的身份进行比较(即它们是参考相同的对象,可以由
is
运算符testing)。
使用is
运算符还有另一个可能的testing。 我们会问这个对象:“你是这个特定对象吗?”
一般来说,我build议使用非数值的第一个testing,当你想比较相同的性质(两个string,两个数字,…)的对象时,使用testing相等,只有当使用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
这些实际上都是不好的做法。 曾几何时,认为随便把“无”和“假”视为相似。 但是,由于Python 2.2这不是最好的策略。
首先,当你做一个if x
或者if not x
types的testing时,Python必须隐含地把x
转换为布尔值。 bool
函数的规则描述了一系列错误的东西; 一切都是真的。 如果x的值不适合布尔值,那么这种隐式转换并不是说明事情的最明确方式。
在Python 2.2之前,没有bool函数,所以更不清楚。
其次,你不应该用== None
testing。 你应该使用“ 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" -- eg 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
, None
, Ellipsis
。 既然你不太可能使用NotImplemented
或者Ellipsis
,并且你永远不会说if x is True
(因为if x
更清晰的话),你将只能testingNone
。
因为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。
这是短路expression式背后的“魔术”,例如:
foo = bar and spam or eggs
这是简写为:
if bar: foo = spam else: foo = eggs
虽然你真的应该写:
foo = spam if bar else egg
如果你问
if not spam: print "Sorry. No SPAM."
垃圾邮件的__nonzero__方法被调用。 从Python手册:
__nonzero__ ( self )被调用来实现真值testing,并且内置操作bool(); 应该返回False或者True,或者等于0或者1的整数。当这个方法没有被定义的时候,__len __()被调用,如果被定义的话(见下面)。 如果一个类既没有定义__len __()也没有定义__nonzero __(),所有的实例都被认为是真的。
如果你问
if spam == None: print "Sorry. No SPAM here either."
用参数None调用垃圾邮件的__eq__方法。
有关定制可能性的更多信息,请参阅https://docs.python.org/reference/datamodel.html#basic-customization中的Python文档;
PEP 8 – Python代码样式指南build议使用是或否,如果您正在testingNone-ness
- Comparisons to singletons like None should always be done with 'is' or 'is not', never the equality operators.
另一方面,如果您testing的不是无关性,则应使用布尔运算符。
这两个比较服务于不同的目的。 前者检查布尔值的东西,第二个检查与None值的身份。
对于第一个例子是更短,看起来更好。 根据其他职位你select还取决于你真正想要做的比较。
答案是“这取决于”。
我使用第一个例子,如果我认为0,“”,[]和False(列表不详)在这种情况下等价于None。
就个人而言,我select了跨语言的一致方法: if (var)
(或等效)只有当var被声明为布尔值时(或者定义为C,我们没有特定的types)。 我甚至在b
加上这些variables(所以它实际上是bVar
),以确保我不会在这里意外地使用另一种types。
我不太喜欢隐式转换为布尔值,更不用说当有许多复杂的规则时。
当然,人们会不同意。 有些更进一步,我在我的工作中看到Java代码中的if (bVar == true)
(对于我的口味来说太冗余了!),另外一些人喜欢太紧凑的语法, while (line = getNextLine())
(对我来说太模糊)。