“==”和“是”之间有区别吗?

时间:2008-09-25 12:27:10

标签: python reference equality semantics

我的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测试的值,看它们是否是同一个对象?

21 个答案:

答案 0 :(得分:818)

如果两个变量指向同一个对象,{p> is将返回True,如果变量引用的对象相等,则返回==

>>> a = [1, 2, 3]
>>> b = a
>>> b is a 
True
>>> b == a
True
>>> b = a[:] # Make a new copy of list `a` via the slice operator, and assign it to variable `b`
>>> 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

请同时参阅this question

答案 1 :(得分:274)

有一个简单的经验法则可以告诉您何时使用==is

  • ==用于值相等。如果您想知道两个对象是否具有相同的值,请使用它。
  • is用于引用相等。如果您想知道两个引用是否引用同一个对象,请使用它。

通常,当您将某些内容与简单类型进行比较时,通常会检查值相等,因此您应该使用==。例如,您的示例的意图可能是检查x的值是否等于2(==),而不是x是否实际上将同一对象称为2。


需要注意的其他事项:由于CPython参考实现的工作方式,如果您错误地使用is来比较整数上的引用相等性,您将得到意外且不一致的结果:

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

这几乎是我们的预期:ab具有相同的值,但却是不同的实体。但是这个呢?

>>> 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的另一个明显原因:当您错误地将其用于值相等时,行为将留给实现。

答案 2 :(得分:33)

==确定值是否相等,而is确定它们是否完全相同且相等。

答案 3 :(得分:23)

  

Python中==is之间是否存在差异?

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

== :检查是否相等 - 语义是等效对象(不一定是同一个对象)将测试相等。正如documentation says

  

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

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

  

运算符isis not测试对象标识:x is y为真   当且仅当xy是同一个对象时。对象标识是   使用id()函数确定。 x is not y产生反转   真理价值。

因此,检查身份与检查对象的ID是否相等是一样的。也就是说,

a is b

与:

相同
id(a) == id(b)

其中id是内置函数,它返回一个整数,"保证在同时存在的对象中是唯一的" (请参阅help(id)),其中ab是任意对象。

其他使用方法

您应该将这些比较用于其语义。使用is检查身份,==检查相等性。

PEP 8,标准库的官方Python风格指南也提到了two use-cases for is

  

None等单身人士的比较应始终使用is或。{   is not,绝不是平等操作符。

     

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

从身份推断平等

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

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

  

相等性比较(==!=)的默认行为基于   对象的身份。因此,实例的相等比较   具有相同身份的结果是平等的,而且是相等的比较   具有不同身份的实例导致不平等。一个   这种默认行为的动机是所有对象的愿望   应该是反身的(即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的整数,此时它在生产中失败。

这是一次生产故障,可能是在代码审查中或可能是样式检查程序中发现的。

我要强调: do not use is to compare integers.

答案 4 :(得分:17)

他们完全不同is检查对象标识,而==检查是否相等(依赖于两个操作数类型的概念)。

is”似乎与小整数(例如5 == 4 + 1)正常工作只是一个幸运的巧合。那是因为CPython optimizes the storage of integers in the range (-5 to 256) by making them singletons。这种行为完全取决于实现,并不保证在各种微小的变革操作下都能保留。

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

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

答案 5 :(得分:16)

is==之间的区别是什么?

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

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

在Python名称中引用对象,例如在这种情况下value1value2引用存储值int的{​​{1}}实例:

1000

enter image description here

因为value1 = 1000 value2 = value1 引用同一个对象value2is会引用==

True

在以下示例中,名称>>> value1 == value2 True >>> value1 is value2 True value1引用不同的value2实例,即使两者都存储相同的整数:

int

enter image description here

因为存储>>> value1 = 1000 >>> value2 = 1000 的相同值(整数)将是==,这就是为什么它经常被称为"值比较"。但是True会返回is,因为它们是不同的对象:

False

何时使用?

通常>>> value1 == value2 True >>> value1 is value2 False 比较快。这就是为什么CPython缓存(或者可能重用将是更好的术语)某些对象,如小整数,一些字符串等等。但这应被视为实现细节可能(即使不太可能)在没有任何警告的情况下随时改变。

如果您:

,则仅应使用is
  • 想要检查两个对象是否真的是同一个对象(不只是相同的"值")。一个例子可以是使用单个对象作为常量。
  • 想要将值与Python constant进行比较。 Python中的常量是:

    • is
    • None 1
    • True 1
    • False
    • NotImplemented
    • Ellipsis
    • 类(例如__debug__int is int
    • 内置模块或第三方模块中可能存在其他常量。例如,来自NumPy模块的np.ma.masked

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

我可以自定义行为吗?

==的某些方面在其他答案中已经没有提及:它是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__True。它可以返回任何东西(但在大多数情况下它应该返回一个布尔值!)。

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

==

>>> import numpy as np >>> np.arange(10) == 2 array([False, False, True, False, False, False, False, False, False, False], dtype=bool) 次检查将始终返回isTrue

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

通常,您不应该进行任何Falseis True检查,因为通常会使用这些"检查"在隐式将 condition 转换为布尔值的上下文中(例如在is False语句中)。所以进行if比较隐式布尔强制转换比做布尔强制转换更多的工作 - 并且你自己限制为布尔值(它不被认为是pythonic)。 / p>

与PEP8一样提及:

  

不要使用is True将布尔值与TrueFalse进行比较。

==

答案 6 :(得分:10)

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

is测试身份 ==测试平等

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

答案 7 :(得分:6)

你的答案是对的。 is运算符比较两个对象的标识。 ==运算符会比较两个对象的值。

对象的标识一旦创建就永远不会改变;你可以把它想象成对象在内存中的地址。

您可以通过定义__cmp__方法或__eq__方法来控制对象值的比较行为。

答案 8 :(得分:4)

查看Stack Overflow问题 Python's “is” operator behaves unexpectedly with integers

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

答案 9 :(得分:3)

==运算符比较两个操作数的值并检查值是否相等。而is运算符检查两个操作数是否都引用相同的对象。

a = [1,2,3,4]
b = a
print(a == b) # true
print(a is b) # true

但如果我们这样做

b = a[:] # b now references a copy of a
print(a == b) # true
print(a is b) # false
print(a is not b) # true

基本上,is可以看作id(a) == id(b)的简写。但是,除此之外,还存在一些运行时环境的古怪之处,这些古怪之处使事情进一步复杂化。与True相比,短字符串和小整数将返回 is ,这是因为Python机器试图为同一对象使用更少的内存。

a = 'python'
b = 'python'

print(a == b) # true
print(a is b) # true

答案 10 :(得分:2)

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

NoneType只有一个实例,即None是一个单例。因此,foo == Nonefoo is None的含义相同。但是is测试更快,Pythonic惯例是使用foo is None

如果您正在对垃圾收集进行一些内省或讨论或检查您的自定义字符串实习小工具是否正常工作,那么您可能有foo的用例bar

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

答案 11 :(得分:2)

他们中的大多数已经回答了问题。正如附加说明(基于我的理解和实验,但不是来自记录的来源),声明

  

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

以上答案应该被理解为

  

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

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

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)

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

答案 12 :(得分:2)

简而言之,package com.qblocks.bfof.entity; import com.qblocks.bfof.rank.RankBase; public class EntityPlayer { public RankBase rank; public int xp; public String name; public int pounds; public EntityPlayer(RankBase rank, int xp, String name, int pounds) { this.rank = rank; this.xp = xp; this.name = name; this.pounds = pounds; } public RankBase getRank() { return rank; } public void setRank(RankBase rank) { this.rank = rank; } public int getXp() { return xp; } public void setXp(int xp) { this.xp = xp; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPounds() { return pounds; } public void setPounds(int pounds) { this.pounds = pounds; } } 检查两个引用是否指向同一对象。is检查两个对象是否具有相同的值。

==

答案 13 :(得分:1)

其实我想把它添加为评论,但不能轻易美化它因此添加作为答案,请不要将此视为答案。

这就是我要理解的 -

  

逐一执行并理解每一步的输出

a = [1,2]
b = [1,2,3]
b.pop()
id(a)
id(b)
a is b
a == b

答案 14 :(得分:1)

由于这篇文章中的其他人详细回答了这个问题,我强调主要是is== 之间的字符串比较这会产生不同的结果,我会敦促程序员小心使用它们。

要进行字符串比较,请务必使用==代替is

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

输出:

str is hello
str == hello
以下示例==is中的

会得到不同的结果:

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

输出:

str == hello sam

<强>结论:

仔细使用is来比较字符串

答案 15 :(得分:0)

is和equals(==)之间的Python区别

  

is运算符可能看起来与相等运算符相同,但   他们不一样。

     

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

     

因此,如果is运算符返回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.

答案 16 :(得分:0)

如果将其与JavaScript进行比较(但是,不建议将一种语言与另一种语言进行比较):

  • 使用is进行严格比较。等效的JavaScript(===
  • 使用==进行相等比较。

答案 17 :(得分:-1)

o1是o2 =&gt;比较o1和o2是否都指向内存中的相同物理位置(换句话说,如果它们是同一个对象)

o1 == o2 =&gt;这里python调用o1的__cmp __(o2)方法,理想情况下应该比较该值并返回True或False。 (换句话说,它比较价值)

对于JAVA人员:

  • 在Java中,确定两个字符串变量是否引用相同 物理内存位置使用 str1 == str2 。 (称为对象 身份,它用 Python编写,因为str1是str2 )。

  • 要比较Java中的字符串值, usestr1.equals(str2);在 Python中, 使用str1 == str2

示例:

class A():
    ...:     def __init__(self,a):
    ...:         self.a = a
    ...:     def __repr__(self):
    ...:         return str(self.a)
    ...:     def __cmp__(self, value):
    ...:         print self.a
    ...:         print value.a
    ...:         return cmp(self.a, value.a)

Python Shell输出:

  

o = A(2)   o1 = o

     

o == o1   2   2   真

     

o是o1   真

     

o1 = A(2)

     

o是o1   假

答案 18 :(得分:-1)

&#34; ==&#34;比较值

&#34;是&#34;比较基础对象

# this pgm is to show you the diff b/n == and is

# a==b and a is b

# == compares values
# is compares references i.e compares wether two variables refer to same object(memory)

a=10
b=10
print(a==b) # returns True as a,b have same value 10 
print(a is b)
# returns True,
# we usually falsey assume that a =10 a new object . b=10 a new obj created
# but actually when b=10 ,nothing but b is pointed to 10 until value of a or b is changed from 10 

a=[1]
b=[1]
print(a==b)
#returns True as a,b have a list element 1
print(a is b)
#returns False because here two different objs are created when initiated with lists

答案 19 :(得分:-2)

是的,两者之间存在差异。

  • '==':按值比较对象。
  • 'in':按引用比较对象。

    a = [1,2,3]  
    b = a # both pointing to same object (memory location)
    
    a == b:  
    True  
    a in b:   
    True  #because a and b are pointing to same object
    

现在让我们考虑一下这个案例:

a = [1,2,3]
b = list(a)  # creating copy of object a

a == b:  
True  # as values are same
a in b:   
False  # because they are pointing to different object.

答案 20 :(得分:-2)

虽然所有这些依赖于异议指针比较与值比较的实现的答案都可能是正确的,但是使用for (key in activeFilters) { if (rows[i][key] === activeFilters[key]) { addRow = true; break; // if one is true, that's good enough for an OR } else { addRow = addRow || false; } } if (addRow) { filteredList.push(row[i]); // reset addRow for the next row addRow = false; } 来确定变量值是否为is时有更深层次的语法原因(在布尔逻辑通常表示为None)。

在关系数据库和其他逻辑系统中,NULL表示实际值是“未知”。因此,逻辑表达式NULL必须始终评估为xx == NULL本身,因为不可能知道NULL,无论它可能具有什么值,都与未知值相同。在更严格遵守布尔逻辑规则的编程语言中,xx(或Python xx == NULL)正确地求值为xx == None,并且必须提供替代方法来确定变量值是否为NULL。由于NULL对象引用的统一性,Python在这方面是一个异常值。但为了清晰和逻辑正确,使用Python None比较运算符在我看来更为健全。