“ foo is None”和“ foo == None”之间有什么区别吗?


217

之间有什么区别:

if foo is None: pass

if foo == None: pass

我在大多数Python代码(以及我自己编写的代码)中看到的约定是前者,但是最近我遇到了使用后者的代码。None是NoneType的一个实例(也是唯一的实例,IIRC),所以没关系,对吗?在任何情况下都有可能吗?

Answers:


253

isTrue如果比较相同的对象实例,则始终返回

==最终由该__eq__()方法确定


>>> class Foo(object):
       def __eq__(self, other):
           return True

>>> f = Foo()
>>> f == None
True
>>> f is None
False

51
您可能需要添加None为单例,因此“ None is None”始终为True。
e-satis

43
您可能还想补充一点,该is操作符无法自定义(由用户定义的类重载)。
martineau 2010年

@study该方法__eq__(self)是一种特殊的内置方法,该方法确定==在Python对象上使用时如何处理。在这里,我们重写了它,以便在==类型对象上使用Foo它时始终返回true。is运算符没有等效的方法,因此is无法以相同的方式更改的行为。
布伦丹

是否因为foo类的定义没有构造函数(即init函数)?
研究

49

您可能需要阅读此对象的标识和等效信息

语句“ is”用于对象标识,它检查对象是否引用相同的实例(内存中的相同地址)。

并且'=='语句引用相等(相同的值)。


嗯,我觉得你的链接改变,除非你有兴趣在如何从蟒蛇调用外部函数
帕特

我只是试过了a=1;b=1;print(a is b) # True。知道为什么a is b即使它们似乎是2个不同的对象(内存中的不同地址),结果也是如此?
约翰尼·丘

24

请注意:

if foo:
  # do something

与以下内容完全相同:

if x is not None:
  # do something

前者是布尔值测试,可以在不同的上下文中评估为false。在布尔值测试中,有很多东西代表假,例如空容器,布尔值。在这种情况下,没有人会得出错误的结论,但是其他事情也会发生。


12

(ob1 is ob2) 等于 (id(ob1) == id(ob2))


6
...但是(ob is ob2)要快很多。Timeit说“(a是b)”是每个循环0.0365微秒,“(id(a)== id(b))”是每个循环0.153微秒。快4.2倍!
AKX

4
is版本不需要函数调用,也完全不需要python-解释器属性查找;如果ob1实际上是ob2,则解释器可以立即回答。
u0b34a0f6ae

17
不,不是的。{} is {}是假的,id({}) == id({})可以(并且在CPython的)真实。请参阅stackoverflow.com/questions/3877230
Piotr Dobrogost,2010年

12

原因foo is None是首选的方式是您可能正在处理一个定义了自己__eq__的对象,并且该对象定义为等于None。因此,foo is None如果需要查看它是否确实存在,请始终使用None


8

没有区别是因为相同的对象当然是相等的。但是,PEP 8明确指出您应该使用is

与单例(如None)的比较应该始终使用is或not(而不是equals运算符)进行。


7

is测试身份,而不是平等。对于您的声明foo is none,Python只是比较对象的内存地址。这意味着您要问的问题是“同一对象有两个名称吗?”

==另一方面,根据__eq__()方法确定是否相等。它不在乎身份。

In [102]: x, y, z = 2, 2, 2.0

In [103]: id(x), id(y), id(z)
Out[103]: (38641984, 38641984, 48420880)

In [104]: x is y
Out[104]: True

In [105]: x == y
Out[105]: True

In [106]: x is z
Out[106]: False

In [107]: x == z
Out[107]: True

None是单例运算符。所以None is None总是真。

In [101]: None is None
Out[101]: True

5

对于“无”,相等(==)和身份(is)之间不应有区别。NoneType可能返回相等性的标识。由于None是唯一可以使用NoneType的实例(我认为这是对的),因此两个操作是相同的。对于其他类型,情况并非总是如此。例如:

list1 = [1, 2, 3]
list2 = [1, 2, 3]
if list1==list2: print "Equal"
if list1 is list2: print "Same"

这将打印“等于”,因为列表具有比较操作,而不是默认返回标识。


5

@ 杰森

我建议按照以下方式使用更多内容

if foo:
    #foo isn't None
else:
    #foo is None

我不喜欢使用“ if foo:”,除非foo真正表示一个布尔值(即0或1)。如果foo是字符串或对象或其他对象,则“ if foo:”可能有效,但对我来说似乎是一个懒惰的快捷方式。如果要检查x是否为None,请说“如果x为None:”。


首选方法是使用“ if var”检查空字符串/列表。布尔转换定义明确,并且更少的代码甚至可以实现更好的性能。例如,没有理由执行“如果len(mylist)== 0”。
truppo,2010年

错误。假设foo =“”。然后if foo将返回false并且注释#foo is None错误。
blokeley 2011年

请注意下注者-我的答案是引用一个已经删除的答案,并对此表示不同意。如果您喜欢我的答案中的代码,则需要upvote。:-)
Graeme Perrow

2

一些更多的细节:

  1. is子句实际上检查两个objects是否在相同的内存位置。即它们是否都指向相同的内存位置并具有相同的id

  2. 作为1的结果,请is确保两个词法表示的objects是否具有相同的属性(attributes-of-attributes ...)

  3. 原始类型等的实例boolintstring(有一些例外),NoneType具有相同的值将总是在相同的存储位置。

例如

>>> int(1) is int(1)
True
>>> str("abcd") is str("abcd")
True
>>> bool(1) is bool(2)
True
>>> bool(0) is bool(0)
True
>>> bool(0)
False
>>> bool(1)
True

而且由于NoneType在python的“查找”表中只能有一个自己的实例,因此前者和后者更像是编写代码的开发人员的编程风格(也许是为了保持一致性),而不是出于任何逻辑上的原因选择一个。


2
大家都在读:不要some_string is "bar"用来比较字符串。这样做没有一个可以接受的理由,当您不期望这样做时,它就会崩溃。它经常工作的事实仅仅是因为CPython知道创建两个具有相同内容的不可变对象是愚蠢的。但这仍然可能发生。
ThiefMaster

@ThiefMaster答案是否容易被误解?但是,再次阅读后,找不到它了(提到“某些例外”)。您的声明仅适用于字符串,不适用int,对吗?
出血

并非如此,但是由于您在回答中包含了该示例,因此我认为警告用户使用该示例是一个坏主意,这是一个好主意。也许在该行后添加类似“#cpython特定/不保证”之类的内容……
ThiefMaster

1

约翰·马钦(John Machin)得出的结论None是单例,这一结论得到了该代码的支持。

>>> x = None
>>> y = None
>>> x == y
True
>>> x is y
True
>>> 

由于None是单身,x == None并且x is None将有同样的结果。但是,从我的美学观点来看,x == None是最好的。


2
我不同意此答案末尾的观点。当明确地与没有对象进行比较时,通常希望所讨论的对象就是该None对象。相比之下,很少有人看到None在其他任何上下文中都没有使用,只是False与其他值是真实的相似。在那种情况下,做类似的事情会更惯用if x: pass
SingleNegationElimination 2011年

0
a is b # returns true if they a and b are true alias
a == b # returns true if they are true alias or they have values that are deemed equivalence 


a = [1,3,4]
b = a[:] #creating copy of list
a is b # if gives false
False
a == b # gives true
True
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.