我见过几个像这样的代码示例:
if not someobj: #do something
但我想知道为什么不这样做:
if someobj == None: #do something
有什么区别吗?一个人比另一个人有优势吗?
在第一个测试中,Python尝试将对象转换为bool
值,如果它不是一个值.大致,我们问的对象是:你有意义吗?这是使用以下算法完成的:
如果对象有一个__nonzero__
特殊的方法(如做数字内置插件,int
和float
),它会调用这个方法.它必须要么返回一个bool
直接使用的int
值,或者False
如果等于零则值.
否则,如果对象有一个__len__
特殊的方法(如做容器内置插件,list
,dict
,set
,tuple
,...),它会调用这个方法,考虑一个容器False
,如果它是空的(长度为零).
否则,True
除非None
在这种情况下考虑对象,否则将考虑该对象False
.
在第二个测试中,比较对象的相等性None
.在这里,我们问对象,"你是否等于这个其他价值?"这是使用以下算法完成的:
如果对象有一个__eq__
方法,则调用它,然后将返回值转换为abool
值并用于确定结果if
.
否则,如果对象有__cmp__
方法,则调用它.此函数必须返回int
指示两个对象的顺序(-1
if self < other
,0
if self == other
,+1
if self > other
).
否则,比较对象的标识(即,它们是对同一对象的引用,可以由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
为boolean.bool
函数的规则描述了一大堆错误的东西; 其他一切都是真的.如果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