为什么使用'=='或'is'比较字符串有时会产生不同的结果?

两个字符串变量设置为相同的值。s1 == s2总是返回True,但s1 is s2有时返回False

如果我打开我的Python解释器并进行相同的is比较,它会成功:

>>> s1 = 'text'>>> s2 = 'text'>>> s1 is s2True

这是为什么?

1639124 次浏览

is关键字是对象标识的测试,而==是值比较。

如果您使用is,当且仅当对象是同一个对象时,结果将为真。然而,只要对象的值相同,==就会为真。

我认为这与这样一个事实有关,即当'is'比较结果为false时,使用了两个不同的对象。如果它的计算结果为true,这意味着在内部它使用了相同的确切对象而不是创建一个新的对象,可能是因为您在2秒左右的时间内创建了它们,并且因为它的优化和使用相同的对象之间没有很大的时间差距。

这就是为什么您应该使用等号操作符==而不是is来比较字符串对象的值。

>>> s = 'one'>>> s2 = 'two'>>> s is s2False>>> s2 = s2.replace('two', 'one')>>> s2'one'>>> s2 is sFalse>>>

在这个例子中,我创建了s2,它是一个不同的字符串对象,以前等于“one”,但它与s不是同一个对象,因为解释器没有使用相同的对象,因为我最初没有将其分配给“one”,如果我有的话,它会使它们成为相同的对象。

is是身份测试,==是相等性测试。您的代码中发生的事情将在解释器中模拟如下:

>>> a = 'pub'>>> b = ''.join(['p', 'u', 'b'])>>> a == bTrue>>> a is bFalse

所以,难怪他们不一样,对吧?

换句话说:a is b相当于id(a) == id(b)

根据我有限的Python经验,is用于比较两个对象,看看它们是否是同一个对象,而不是两个具有相同值的不同对象。==用于确定值是否相同。

这里有一个很好的例子:

>>> s1 = u'public'>>> s2 = 'public'>>> s1 is s2False>>> s1 == s2True

s1是Unicode字符串,s2是普通字符串。它们不是相同的类型,但值相同。

我相信这就是所谓的“内部”字符串。Python这样做,Java也是如此,C和C++在优化模式下编译时也是如此。

如果您使用两个相同的字符串,而不是通过创建两个字符串对象来浪费内存,所有具有相同内容的内部字符串都指向相同的内存。

这导致Python“is”运算符返回True,因为两个具有相同内容的字符串指向同一个字符串对象。这也会发生在Java和C中。

不过,这只对节省内存有用。您不能依赖它来测试字符串相等性,因为各种解释器和编译器以及JIT引擎并不总是这样做。

这里的其他答案是正确的:is用于身份比较,而==用于平等比较。由于您关心的是相等(两个字符串应该包含相同的字符),在这种情况下,is运算符是错误的,您应该使用==代替。

is交互工作的原因是(大多数)字符串文字默认为被拘留。来自维基百科:

内部字符串加速字符串比较,有时是一个性能瓶颈(例如编译器和动态编程语言运行时)严重依赖哈希表字符串键。没有实习,检查两个不同的字符串是平等的,包括检查每两个字符串的字符。这是原因有几个:它是的长度为O(n)字符串;它通常需要读取从记忆的几个区域,其中花时间;和阅读填满了处理器缓存,意味着更少缓存可用于其他需求。随着嵌入字符串,一个简单的对象身份验证就足够了最初的实习操作;这是通常实现为指针平等测试,通常只有一个没有记忆体的机器指令#36825;的参考。

所以,当你的程序中有两个字符串字面量(从字面上输入到程序源代码中的单词,用引号包围)具有相同的值时,Python编译器会自动实习字符串,使它们都存储在同一个内存位置。(请注意,这不会发生总是,并且发生这种情况的规则非常复杂,所以请不要在生产代码中依赖这种行为!)

由于在您的交互式会话中,两个字符串实际上存储在相同的内存位置,因此它们具有相同的身份,因此is运算符按预期工作。但是如果您通过其他方法构造字符串(即使该字符串包含完全相同的字符),那么该字符串可能是平等,但它不是相同的字符串-也就是说,它具有不同的身份,因为它存储在内存中的不同位置。

最后要注意的是,您可以使用#0函数来确保您获得对同一字符串的引用:

>>> from sys import intern>>> a = intern('a')>>> a2 = intern('a')>>> a is a2True

如上所述,您不应该使用is来确定字符串的相等性。但这可能有助于了解您是否对使用is有某种奇怪的要求。

请注意,intern函数曾经是Python 2上的内置函数,但被移动到Python 3中的sys模块。

如果你不确定你在做什么,使用'=='。如果你对它有更多的了解,你可以用'is'来表示已知对象,比如'无'。

否则,你最终会想知道为什么事情不起作用以及为什么会发生这种情况:

>>> a = 1>>> b = 1>>> b is aTrue>>> a = 6000>>> b = 6000>>> b is aFalse

我甚至不确定是否可以保证在不同的python版本/实现之间保持不变。

这是一个附带说明,但在惯用的Python中,您经常会看到以下内容:

if x is None:# Some clauses

这是安全的,因为保证有一个Null对象的实例(即无)

is是身份测试,==是相等性测试。这意味着is是一种检查两个事物是否是相同事物或只是等效的方法。

假设你有一个简单的person对象。如果它被命名为'Jack'并且是'23'岁,它相当于另一个23岁的Jack,但它不是同一个人。

class Person(object):def __init__(self, name, age):self.name = nameself.age = age
def __eq__(self, other):return self.name == other.name and self.age == other.age
jack1 = Person('Jack', 23)jack2 = Person('Jack', 23)
jack1 == jack2 # Truejack1 is jack2 # False

他们年龄相同,但不是同一个人。一个字符串可能等价于另一个字符串,但它不是同一个对象。

实际上,is操作符检查身份,==操作符检查相等性。

从语言参考:

类型几乎影响对象行为的所有方面。甚至对象标识的重要性也在某种意义上受到影响:对于不可变类型,操作计算新值实际上可能会返回对具有相同类型和值的任何现有对象的引用,而对于可变对象,这是不允许的。例如,在a=1; b=1之后,a和b可能引用也可能不引用值为1的同一个对象,这取决于实现,但是在c = []; d之后 = [], c和d保证引用两个不同的、唯一的、新创建的空列表。(注意c=d=[]将相同的对象分配给c和d。)

因此,从上述语句中,我们可以推断出字符串是不可变类型,当使用“is”检查时可能会失败,当使用“is”检查时可能会成功。

这同样适用于inttuple,它们也是不可变类型。

is是身份测试,==是相等性测试(参见Python留档)。

在大多数情况下,如果a is b,那么a == b。但也有例外,例如:

>>> nan = float('nan')>>> nan is nanTrue>>> nan == nanFalse

因此,您只能使用is进行身份测试,而不能进行相等性测试。

==运算符测试值等价性。is运算符测试对象标识,Python测试两者是否真的是同一个对象(即,存在于内存中的同一个地址)。

>>> a = 'banana'>>> b = 'banana'>>> a is bTrue

在这个例子中,Python只创建了一个字符串对象,ab都引用了它。原因是Python内部缓存并重用了一些字符串作为优化。内存中真的只有一个字符串“banana”,由a和b共享。要触发正常行为,你需要使用更长的字符串:

>>> a = 'a longer banana'>>> b = 'a longer banana'>>> a == b, a is b(True, False)

当你创建两个列表时,你会得到两个对象:

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

在这种情况下,我们会说两个列表是等价的,因为它们具有相同的元素,但不完全相同,因为它们不是同一个对象。如果两个对象相同,它们也是等价的,但如果它们是等价的,它们不一定相同。

如果a引用了一个对象,而你赋值了b = a,那么两个变量都引用了同一个对象:

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

参考https://greenteapress.com/wp/think-python-2e/

is将比较内存位置。它用于对象级比较。

==将比较程序中的变量。它用于在值级别进行检查。

is检查地址级别等价性

==检查值级别等价

在处理这个问题时,我们必须清楚的基本概念是理解==之间的区别。

"is"is将比较内存位置。如果id(a)==id(b),则a is b返回true,否则返回false。

所以,我们可以说用于比较内存位置。然而,

==用于相等性测试,这意味着它只比较结果值。下面显示的代码可以作为上述给定理论的示例。

代码

点击这里查看代码

在字符串文字(没有分配给变量的字符串)的情况下,内存地址将与图中所示相同。所以,id(a)==id(b)。这是不言自明的