629

我的Google-fu让我失望了。

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

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

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

这是否适用于您将要比较实例的对象(list比如说)?

好的,所以这种回答我的问题:

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

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

那么==测试值在哪里is测试以查看它们是否是同一个对象?

4

14 回答 14

1060

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

>>> 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

请同时查看这个问题

于 2008-09-25T12:32:37.473 回答
362

有一个简单的经验法则可以告诉您何时使用==or 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

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

于 2009-07-06T06:22:52.760 回答
54

==Python和isPython之间有区别吗?

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

==: 检查相等性 - 语义是等效对象(不一定是同一个对象)将测试为相等。正如文档所说

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

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

对象身份的运算符is和测试:当且仅当和是同一个对象时为真。使用该函数确定对象身份。产生逆真值。is notx is yxyid()x is not y

因此,身份检查与检查对象 ID 的相等性相同。那是,

a is b

是相同的:

id(a) == id(b)

whereid是返回一个整数的内置函数,该整数“保证在同时存在的对象中是唯一的”(参见 参考资料help(id)),并且 whereab是任意对象。

其他使用说明

您应该将这些比较用于它们的语义。用于is检查身份和==检查相等性。

所以一般来说,我们is用来检查身份。当我们检查一个只应该在内存中存在一次的对象时,这通常很有用,在文档中称为“单例”。

用例is包括:

  • None
  • 枚举值(使用 enum 模块中的枚举时)
  • 通常是模块
  • 通常是类定义产生的类对象
  • 通常由函数定义产生的函数对象
  • 任何其他应该只在内存中存在一次的东西(通常都是单例)
  • 一个你想要的特定对象

通常的用例==包括:

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

再次,一般用例==是,您想要的对象可能不是同一个对象,而是可能是等价的对象

PEP 8个方向

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

与单例的比较None应该总是使用isor is not,而不是相等运算符。

if x另外,当你真正的意思时要小心写作if x is not None——例如,当测试一个默认为的变量或参数是否None 被设置为其他值时。另一个值可能具有在布尔上下文中可能为假的类型(例如容器)!

从身份推断平等

如果is为真,则通常可以推断出相等性——从逻辑上讲,如果一个对象是它自己,那么它应该测试为与它自己等价。

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

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

并为保持一致性,建议:

平等比较应该是自反的。换句话说,相同的对象应该比较相等:

x is 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

一个警示故事:

问题是试图用来is比较整数。您不应假设整数的实例与通过另一个引用获得的实例相同。这个故事解释了原因。

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

哇,这可能会导致一些阴险的错误。我有一些代码可以检查 a 是否为 b,因为 a 和 b 通常是很小的数字,所以可以按我的意愿工作。该错误仅在今天发生,经过六个月的生产,因为 a 和 b 终于大到不能被缓存。– gwg

它在开发中起作用。它可能已经通过了一些单元测试。

它在生产中工作 - 直到代码检查大于 256 的整数,此时它在生产中失败。

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

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

于 2018-01-05T19:33:55.397 回答
43

==确定值是否相等,同时is确定它们是否是完全相同的对象。

于 2008-09-25T12:31:12.533 回答
26

is和有什么区别==

==并且is是不同的比较!正如其他人已经说过的那样:

  • ==比较对象的值。
  • is比较对象的引用。

在 Python 中,名称指的是对象,例如在这种情况下value1value2指的是int存储值的实例1000

value1 = 1000
value2 = value1

在此处输入图像描述

因为value2指的是同一个对象is,并且==会给出True

>>> value1 == value2
True
>>> value1 is value2
True

在以下示例中,名称value1value2引用不同的int实例,即使两者都存储相同的整数:

>>> value1 = 1000
>>> value2 = 1000

在此处输入图像描述

因为存储了相同的值(整数)==will be True,这就是为什么它通常被称为“值比较”。但是is会返回False,因为这些是不同的对象:

>>> value1 == value2
True
>>> value1 is value2
False

什么时候用哪个?

通常is是一个更快的比较。这就是为什么 CPython 缓存(或者可能重用是更好的术语)某些对象,如小整数、一些字符串等。但这应该被视为可能(即使不太可能)在任何时候更改而不会发出警告的实现细节。

您应该只在以下情况下使用is

  • 想要检查两个对象是否真的是同一个对象(不仅仅是同一个“值”)。一个示例是,如果使用单例对象作为常量。

  • 想要将值与Python常量进行比较。Python中的常量是:

    • None
    • True1
    • False1
    • NotImplemented
    • Ellipsis
    • __debug__
    • 类(例如int is intint is float
    • 内置模块或第 3 方模块中可能有额外的常量。例如np.ma.masked来自 NumPy 模块)

所有其他情况下,您应该使用它==来检查是否相等。

我可以自定义行为吗?

==其他答案中尚未提及某些方面:它是Pythons "Data model"的一部分。这意味着可以使用该__eq__方法自定义其行为。例如:

class MyClass(object):
    def __init__(self, val):
        self._value = val

    def __eq__(self, other):
        print('__eq__ method called')
        try:
            return self._value == other._value
        except AttributeError:
            raise TypeError('Cannot compare {0} to objects of type {1}'
                            .format(type(self), type(other)))

这只是一个人为的例子来说明该方法是真正被调用的:

>>> MyClass(10) == MyClass(10)
__eq__ method called
True

请注意,默认情况下(如果__eq__在类或超类中找不到其他实现)__eq__使用is

class AClass(object):
    def __init__(self, value):
        self._value = value

>>> a = AClass(10)
>>> b = AClass(10)
>>> a == b
False
>>> a == a

__eq__因此,如果您想要“更多”而不仅仅是自定义类的参考比较,那么实现它实际上很重要!

另一方面,您不能自定义is检查。如果您有相同的参考,它将始终进行比较。

这些比较是否总是返回布尔值?

因为__eq__可以重新实现或覆盖,所以不限于 returnTrueFalse. 它可以返回任何东西(但在大多数情况下它应该返回一个布尔值!)。

例如对于 NumPy 数组,==将返回一个数组:

>>> import numpy as np
>>> np.arange(10) == 2
array([False, False,  True, False, False, False, False, False, False, False], dtype=bool)

但是is支票总是会返回TrueFalse


1正如 Aaron Hall 在评论中提到的:

通常,您不应执行任何is True或检查,因为通常在将条件隐式转换为布尔值(例如在语句中)is False的上下文中使用这些“检查” 。因此,进行比较隐式布尔转换比仅仅进行布尔转换所做的工作更多——并且您将自己限制为布尔值(这不被认为是 pythonic)。ifis True

就像 PEP8 提到的:

不要将布尔值与TrueFalse使用==.

Yes:   if greeting:
No:    if greeting == True:
Worse: if greeting is True:
于 2018-01-19T22:21:25.820 回答
21

他们完全不同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
于 2008-09-25T17:15:38.323 回答
12

https://docs.python.org/library/stdtypes.html#comparisons

is身份 ==测试 平等测​​试

每个(小)整数值都映射到单个值,因此每 3 是相同且相等的。这是一个实现细节,不是语言规范的一部分

于 2008-09-25T12:31:57.757 回答
7

你的答案是正确的。运算符比较两个对象的is身份。运算符比较两个对象的==值。

对象的身份一旦创建就永远不会改变;您可能会将其视为对象在内存中的地址。

您可以通过定义__cmp__方法或丰富的比较方法(如__eq__.

于 2008-09-25T12:34:18.920 回答
5

查看 Stack Overflow 问题Python 的“is”运算符对整数的行为异常

它主要归结为“ is”检查它们是否是同一个对象,而不仅仅是彼此相等(256 以下的数字是一种特殊情况)。

于 2009-07-06T06:20:00.237 回答
5

简而言之,is检查两个引用是否指向同一个对象。==检查两个对象是否具有相同的值。

a=[1,2,3]
b=a        #a and b point to the same object
c=list(a)  #c points to different object 

if a==b:
    print('#')   #output:#
if a is b:
    print('##')  #output:## 
if a==c:
    print('###') #output:## 
if a is c:
    print('####') #no output as c and a point to different object 
于 2018-07-29T20:17:41.880 回答
3

正如 John Feminella 所说,大多数时候您将使用 == 和 != 因为您的目标是比较值。我只想对你在剩下的时间里会做什么进行分类:

NoneType 只有一个实例,即 None 是单例。因此foo == Nonefoo is None意思相同。但是is测试更快,Pythonic 约定是使用foo is None.

如果您正在做一些自省或处理垃圾收集或检查您定制的字符串实习小工具是否正常工作等,那么您可能有foois的用例bar

True 和 False 也是(现在)单例,但没有用例 forfoo == True也没有用例foo is True.

于 2009-07-06T08:50:52.663 回答
3

正如这篇文章中的其他人详细回答了比较对象或变量之间的区别==和比较的问题is,我将主要强调可以给出不同结果的字符串is之间的比较,我会敦促程序员谨慎使用它们。==

对于字符串比较,请确保使用==而不是is

str = 'hello'
if (str is 'hello'):
    print ('str is hello')
if (str == 'hello'):
    print ('str == hello')

出去:

str is hello
str == hello

在下面的例子中==is会得到不同的结果:

str2 = 'hello sam'
    if (str2 is 'hello sam'):
        print ('str2 is hello sam')
    if (str2 == 'hello sam'):
        print ('str2 == hello sam')

出去:

str2 == hello sam

结论与分析:

小心使用is来比较字符串。由于is用于比较对象,并且在 Python 3+ 中,每个变量(例如字符串)都解释为对象,让我们看看上面的段落中发生了什么。

在 python 中,有一个id函数可以显示对象在其生命周期内的唯一常量。此 id 在 Python 解释器的后端使用is关键字来比较两个对象。

str = 'hello'
id('hello')
> 140039832615152
id(str)
> 140039832615152

str2 = 'hello sam'
id('hello sam')
> 140039832615536
id(str2)
> 140039832615792
于 2018-02-01T15:56:52.980 回答
3

他们中的大多数人已经回答了这一点。就像一个附加说明(基于我的理解和实验,但不是来自记录的来源),声明

== 如果变量引用的对象相等

从上面的答案应该被理解为

== 如果变量引用的对象相等且对象属于同一类型/类

. 我根据以下测试得出了这个结论:

list1 = [1,2,3,4]
tuple1 = (1,2,3,4)

print(list1)
print(tuple1)
print(id(list1))
print(id(tuple1))

print(list1 == tuple1)
print(list1 is tuple1)

这里列表和元组的内容相同,但类型/类不同。

于 2018-03-07T08:05:20.210 回答
3

Python is 和 equals(==) 的区别

is 运算符可能看起来与相等运算符相同,但它们并不相同。

is 检查两个变量是否指向同一个对象,而 == 符号检查两个变量的值是否相同。

因此,如果 is 运算符返回 True,则等式肯定为 True,但相反的结果可能为 True,也可能不是 True。

这是一个示例来演示相似性和差异。

>>> a = b = [1,2,3]
>>> c = [1,2,3]
>>> a == b
True
>>> a == c
True
>>> a is b
True
>>> a is c
False
>>> a = [1,2,3]
>>> b = [1,2]
>>> a == b
False
>>> a is b
False
>>> del a[2]
>>> a == b
True
>>> a is b
False
Tip: Avoid using is operator for immutable types such as strings and numbers, the result is unpredictable.
于 2018-08-08T12:30:33.620 回答