【发布时间】:2010-09-06 19:07:22
【问题描述】:
两者有什么区别:
if foo is None: pass
和
if foo == None: pass
我在大多数 Python 代码(以及我自己编写的代码)中看到的约定是前者,但我最近遇到了使用后者的代码。 None 是 NoneType 的一个实例(也是唯一的实例,IIRC),所以没关系,对吧?有没有什么情况下可能?
【问题讨论】:
标签: python
两者有什么区别:
if foo is None: pass
和
if foo == None: pass
我在大多数 Python 代码(以及我自己编写的代码)中看到的约定是前者,但我最近遇到了使用后者的代码。 None 是 NoneType 的一个实例(也是唯一的实例,IIRC),所以没关系,对吧?有没有什么情况下可能?
【问题讨论】:
标签: python
is 在比较同一个对象实例时总是返回True
而== 最终由__eq__() 方法确定
即
>>> class Foo(object):
def __eq__(self, other):
return True
>>> f = Foo()
>>> f == None
True
>>> f is None
False
【讨论】:
is 运算符不能自定义(被用户定义的类重载)。
__eq__(self) 方法是一个特殊的内置方法,用于确定在 Python 对象上使用时如何处理 ==。这里我们重写了它,所以当== 用于Foo 类型的对象时,它总是返回true。 is 运算符没有等效的方法,因此 is 的行为不能以相同的方式更改。
您可能想阅读此object identity and equivalence。
语句'is'用于对象标识,它检查对象是否引用相同的实例(内存中的相同地址)。
而 '==' 语句指的是相等(相同的值)。
【讨论】:
a=1;b=1;print(a is b) # True。知道为什么a is b 是真的,即使它们似乎是 2 个不同的对象(内存中的不同地址)?
请注意:
if foo:
# do something
不完全等同于:
if x is not None:
# do something
前者是一个布尔值测试,可以在不同的上下文中评估为 false。在布尔值测试中,有很多东西代表错误,例如空容器、布尔值。在这种情况下,None 的计算结果也为 false,但其他情况也一样。
【讨论】:
(ob1 is ob2) 等于 (id(ob1) == id(ob2))
【讨论】:
is 版本不需要函数调用,也不需要 python-interpreter 属性查找;如果 ob1 实际上是 ob2,解释器可以立即回答。
{} is {} 是假的,id({}) == id({}) 可以是(在 CPython 中 是)真。见stackoverflow.com/questions/3877230
foo is None 是首选方式的原因是您可能正在处理一个定义了自己的__eq__ 的对象,并且该对象将对象定义为等于无。所以,如果你需要查看它是否是None,请始终使用foo is None。
【讨论】:
没有区别,因为相同的对象当然是相等的。但是,PEP 8 明确指出您应该使用is:
与 None 等单例的比较应始终使用 is 或 not,而不是相等运算符。
【讨论】:
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
【讨论】:
对于 None,等式 (==) 和身份 (is) 之间不应有区别。 NoneType 可能返回相等的身份。由于 None 是唯一可以使用 NoneType 的实例(我认为这是真的),因此这两个操作是相同的。在其他类型的情况下,情况并非总是如此。例如:
list1 = [1, 2, 3]
list2 = [1, 2, 3]
if list1==list2: print "Equal"
if list1 is list2: print "Same"
这将打印“Equal”,因为列表有一个不是默认返回标识的比较操作。
【讨论】:
@Jason:
我建议使用更多类似的东西
if foo: #foo isn't None else: #foo is None
我不喜欢使用“if foo:”,除非 foo 真正代表一个布尔值(即 0 或 1)。如果 foo 是一个字符串或一个对象或其他东西,“if foo:”可能会起作用,但它对我来说似乎是一个懒惰的捷径。如果您正在检查 x 是否为 None,请说“如果 x 为 None:”。
【讨论】:
if foo会返回false,评论#foo is None是错误的。
更多细节:
is 子句实际上检查两个objects 是否相同
内存位置与否。即它们是否都指向同一个
内存位置并具有相同的id。
作为 1 的结果,is 确保两个词法表示的objects 是否具有相同的属性(attributes-of-attributes...)
基元类型的实例化,如bool、int、string(有一些例外)、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 的“查找”表中只能有一个自身实例,因此前者和后者更像是编写代码的开发人员的一种编程风格(可能是为了保持一致性)而不是有任何微妙的逻辑理由来选择一个而不是另一个。
【讨论】:
some_string is "bar" 来比较字符串。没有一个可以接受的理由这样做,并且当您不期望它时它会中断。它经常工作的事实仅仅是因为 CPython 知道创建两个具有相同内容的不可变对象是愚蠢的。但它仍然可能发生。
int,对吗?
John Machin 关于None 是单例的结论是由这段代码支持的结论。
>>> x = None
>>> y = None
>>> x == y
True
>>> x is y
True
>>>
由于None 是单例,x == None 和x is None 将具有相同的结果。但是,在我看来,x == None 是最好的。
【讨论】:
None 对象。相比之下,除了与False 相似且其他值为真值外,很少有人在任何其他上下文中看到 None 。在这些情况下,做类似if x: pass 之类的事情会更惯用
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
【讨论】: