我的Google-fu让我失望了

在Python中,以下两个相等测试是否等效?

n = 5
# Test one.
if n == 5:
    print 'Yay!'

# Test two.
if n is 5:
    print 'Yay!'

这是否适用于对象,你将比较实例(一个列表说)?

这就回答了我的问题

L = []
L.append(1)
if L == [1]:
    print 'Yay!'
# Holds true, but...

if L is [1]:
    print 'Yay!'
# Doesn't.

所以==测试值测试是看他们是否相同的对象?


当前回答

在Python中==和Is有区别吗?

是的,它们有一个非常重要的区别。

==: check for equal——语义是等价的对象(不一定是同一个对象)将被测试为相等。如文档所述:

运算符<、>、==、>=、<=和!=比较两个对象的值。

Is:检查身份——语义是对象(在内存中)是对象。同样,文档说:

操作符is和is not测试对象的同一性:x是y是真 当且仅当x和y是同一个对象。对象恒等式是 使用id()函数确定。X不是y会得到逆函数 真值。

因此,检查标识符与检查对象的id是否相等是一样的。也就是说,

a is b

等于:

id(a) == id(b)

其中id是内建函数,返回一个“在同时存在的对象中保证唯一”的整数(参见help(id)),其中a和b是任意对象。

其他使用说明

您应该使用这些语义比较。用is检查身份,用==检查是否相等。

一般来说,我们用is来检查恒等式。当我们检查一个在内存中只存在一次的对象时,这通常是有用的,在文档中称为“单例”。

is的用例包括:

没有一个 enum值(当使用enum模块中的Enums时) 通常模块 通常是类定义产生的类对象 通常是由函数定义产生的函数对象 任何其他在内存中只存在一次的对象(通常都是单例对象) 一个你想要的特定对象

==的常用用例包括:

数字,包括整数 字符串 列表 集 字典 自定义可变对象 其他内建的不可变对象,在大多数情况下

同样,对于==,一般的用例是,你想要的对象可能不是同一个对象,相反,它可能是一个等价的对象

PEP 8说明

标准库的官方Python风格指南PEP 8也提到了is的两个用例:

与像None这样的单例对象的比较应该总是使用is或 不是,不是相等运算符。 另外,当你真正的意思是如果x不是None时,要注意写if x 例如,当测试一个变量或参数是否默认为None时 被设置为其他值。另一个值可能具有类型(例如 作为容器),在布尔上下文中可能是假的!

由同一推断相等

如果is为真,通常可以推断相等性-逻辑上,如果一个对象是自身,那么它应该测试为等效于自身。

在大多数情况下,这个逻辑是正确的,但它依赖于__eq__特殊方法的实现。正如医生所说,

相等性比较(==和!=)的默认行为是基于 对象的身份。因此,实例的相等性比较 具有相同的同一性结果就等于相等,而相等的比较 具有不同身份的实例会导致不平等。一个 这种默认行为的动机是所有对象的愿望 应该是自反的(即x是y意味着x == y)。

为了保持一致性,建议:

平等比较应该是自反性的。换句话说,完全相同 对象的比较应该相等: X是y意味着X == y

我们可以看到这是自定义对象的默认行为:

>>> class Object(object): pass
>>> obj = Object()
>>> obj2 = Object()
>>> obj == obj, obj is obj
(True, True)
>>> obj == obj2, obj is obj2
(False, False)

反证法通常也是正确的——如果某物测试为不相等,你通常可以推断出它们不是同一个物体。

由于相等性测试可以自定义,因此这种推断并不总是适用于所有类型。

一个例外

一个值得注意的例外是nan——它总是被测试为不等于自身:

>>> nan = float('nan')
>>> nan
nan
>>> nan is nan
True
>>> nan == nan           # !!!!!
False

检查身份比检查相等性要快得多(相等性可能需要递归地检查成员)。

但它不能代替相等,因为你可能会发现多个对象是相等的。

注意,比较列表和元组的相等性将假定对象的身份相等(因为这是一个快速检查)。如果逻辑不一致,就会产生矛盾——就像nan一样:

>>> [nan] == [nan]
True
>>> (nan,) == (nan,)
True

一个警世故事:

问题是要比较整数。您不应该假定一个整数的实例与另一个引用获得的实例是相同的实例。下面这个故事解释了原因。

一位评论者的代码依赖于小整数(-5到256)在Python中是单例,而不是检查是否相等。

哇,这可能会导致一些潜伏的bug。我写了一些代码来检查a是不是b,这就像我想要的那样,因为a和b通常都是很小的数字。这个错误直到今天才出现,因为a和b终于大到不能被缓存了。——gwg

它在开发过程中发挥了作用。它可能通过了一些单元测试。

它在生产中工作-直到代码检查大于256的整数,在这一点上它在生产中失败了。

这是一个生产失败,可以在代码检查或样式检查器中发现。

让我强调一下:不要使用is来比较整数。

其他回答

你的答案是正确的。is操作符比较两个对象的标识符。==操作符比较两个对象的值。

对象的标识一旦创建就不会改变;你可以把它看作是对象在内存中的地址。

你可以通过定义__cmp__方法或像__eq__这样的富比较方法来控制对象值的比较行为。

有一个简单的经验法则告诉你什么时候使用==或is。

==表示价值相等。当你想知道两个对象是否有相同的值时使用它。 Is是参考等式。当您想知道两个引用是否指向同一个对象时,可以使用它。

一般来说,当你比较一个简单类型时,你通常会检查值是否相等,所以你应该使用==。例如,您的示例的目的可能是检查x是否有一个等于2的值(==),而不是检查x是否字面上指的是与2相同的对象。


另外需要注意的是:由于CPython引用实现的工作方式,如果你错误地使用is比较整数上的引用相等性,你会得到意外和不一致的结果:

>>> a = 500
>>> b = 500
>>> a == b
True
>>> a is b
False

这和我们预期的差不多:a和b有相同的值,但是不同的实体。但是这个呢?

>>> c = 200
>>> d = 200
>>> c == d
True
>>> c is d
True

这与先前的结果不一致。这是怎么回事?事实证明,Python的参考实现缓存范围为-5..出于性能考虑,将256作为单例实例。下面是一个例子:

>>> for i in range(250, 260): a = i; print "%i: %s" % (i, a is int(str(i)));
... 
250: True
251: True
252: True
253: True
254: True
255: True
256: True
257: False
258: False
259: False

这是不使用的另一个明显原因:当您错误地将其用于值相等时,行为将留给实现。

在Python中==和Is有区别吗?

是的,它们有一个非常重要的区别。

==: check for equal——语义是等价的对象(不一定是同一个对象)将被测试为相等。如文档所述:

运算符<、>、==、>=、<=和!=比较两个对象的值。

Is:检查身份——语义是对象(在内存中)是对象。同样,文档说:

操作符is和is not测试对象的同一性:x是y是真 当且仅当x和y是同一个对象。对象恒等式是 使用id()函数确定。X不是y会得到逆函数 真值。

因此,检查标识符与检查对象的id是否相等是一样的。也就是说,

a is b

等于:

id(a) == id(b)

其中id是内建函数,返回一个“在同时存在的对象中保证唯一”的整数(参见help(id)),其中a和b是任意对象。

其他使用说明

您应该使用这些语义比较。用is检查身份,用==检查是否相等。

一般来说,我们用is来检查恒等式。当我们检查一个在内存中只存在一次的对象时,这通常是有用的,在文档中称为“单例”。

is的用例包括:

没有一个 enum值(当使用enum模块中的Enums时) 通常模块 通常是类定义产生的类对象 通常是由函数定义产生的函数对象 任何其他在内存中只存在一次的对象(通常都是单例对象) 一个你想要的特定对象

==的常用用例包括:

数字,包括整数 字符串 列表 集 字典 自定义可变对象 其他内建的不可变对象,在大多数情况下

同样,对于==,一般的用例是,你想要的对象可能不是同一个对象,相反,它可能是一个等价的对象

PEP 8说明

标准库的官方Python风格指南PEP 8也提到了is的两个用例:

与像None这样的单例对象的比较应该总是使用is或 不是,不是相等运算符。 另外,当你真正的意思是如果x不是None时,要注意写if x 例如,当测试一个变量或参数是否默认为None时 被设置为其他值。另一个值可能具有类型(例如 作为容器),在布尔上下文中可能是假的!

由同一推断相等

如果is为真,通常可以推断相等性-逻辑上,如果一个对象是自身,那么它应该测试为等效于自身。

在大多数情况下,这个逻辑是正确的,但它依赖于__eq__特殊方法的实现。正如医生所说,

相等性比较(==和!=)的默认行为是基于 对象的身份。因此,实例的相等性比较 具有相同的同一性结果就等于相等,而相等的比较 具有不同身份的实例会导致不平等。一个 这种默认行为的动机是所有对象的愿望 应该是自反的(即x是y意味着x == y)。

为了保持一致性,建议:

平等比较应该是自反性的。换句话说,完全相同 对象的比较应该相等: X是y意味着X == y

我们可以看到这是自定义对象的默认行为:

>>> class Object(object): pass
>>> obj = Object()
>>> obj2 = Object()
>>> obj == obj, obj is obj
(True, True)
>>> obj == obj2, obj is obj2
(False, False)

反证法通常也是正确的——如果某物测试为不相等,你通常可以推断出它们不是同一个物体。

由于相等性测试可以自定义,因此这种推断并不总是适用于所有类型。

一个例外

一个值得注意的例外是nan——它总是被测试为不等于自身:

>>> nan = float('nan')
>>> nan
nan
>>> nan is nan
True
>>> nan == nan           # !!!!!
False

检查身份比检查相等性要快得多(相等性可能需要递归地检查成员)。

但它不能代替相等,因为你可能会发现多个对象是相等的。

注意,比较列表和元组的相等性将假定对象的身份相等(因为这是一个快速检查)。如果逻辑不一致,就会产生矛盾——就像nan一样:

>>> [nan] == [nan]
True
>>> (nan,) == (nan,)
True

一个警世故事:

问题是要比较整数。您不应该假定一个整数的实例与另一个引用获得的实例是相同的实例。下面这个故事解释了原因。

一位评论者的代码依赖于小整数(-5到256)在Python中是单例,而不是检查是否相等。

哇,这可能会导致一些潜伏的bug。我写了一些代码来检查a是不是b,这就像我想要的那样,因为a和b通常都是很小的数字。这个错误直到今天才出现,因为a和b终于大到不能被缓存了。——gwg

它在开发过程中发挥了作用。它可能通过了一些单元测试。

它在生产中工作-直到代码检查大于256的整数,在这一点上它在生产中失败了。

这是一个生产失败,可以在代码检查或样式检查器中发现。

让我强调一下:不要使用is来比较整数。

如果两个变量指向同一个对象(在内存中),则返回True,如果变量引用的对象相等则返回==。

>>> a = [1, 2, 3]
>>> b = a
>>> b is a 
True
>>> b == a
True

# Make a new copy of list `a` via the slice operator, 
# and assign it to variable `b`
>>> b = a[:] 
>>> b is a
False
>>> b == a
True

在您的情况下,第二个测试只能工作,因为Python缓存小整数对象,这是一个实现细节。对于较大的整数,这行不通:

>>> 1000 is 10**3
False
>>> 1000 == 10**3
True

这同样适用于字符串字面量:

>>> "a" is "a"
True
>>> "aa" is "a" * 2
True
>>> x = "a"
>>> "aa" is x * 2
False
>>> "aa" is intern(x*2)
True

请看这个问题。

它们完全不同。Is检查对象的同一性,而==检查相等性(这一概念取决于两个操作数的类型)。

这只是一个幸运的巧合,“is”似乎正确地适用于小整数(例如5 == 4+1)。这是因为CPython通过使整数为单例来优化范围(-5到256)内的整数的存储。这种行为完全依赖于实现,并且不能保证在所有形式的小型转换操作下都能保留。

例如,Python 3.5也创建了短字符串单例,但将它们切片会破坏这种行为:

>>> "foo" + "bar" == "foobar"
True
>>> "foo" + "bar" is "foobar"
True
>>> "foo"[:] + "bar" == "foobar"
True
>>> "foo"[:] + "bar" is "foobar"
False