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

如果我打开我的Python解释器,并做同样的比较,它成功了:

>>> s1 = 'text'
>>> s2 = 'text'
>>> s1 is s2
True

为什么会这样?


当前回答

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

这里有一个很好的例子:

>>> s1 = u'public'
>>> s2 = 'public'
>>> s1 is s2
False
>>> s1 == s2
True

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

其他回答

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

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

所以,我们可以说is是用来比较内存位置的。然而,

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

Code

对于字符串字面值(未分配给变量的字符串),内存地址将与图中所示相同。所以,id (a) (b) = = id。剩下的是不言自明的。

==运算符测试值等价性。is操作符测试对象的身份,Python测试两者是否真的是相同的对象(即,在内存中存在相同的地址)。

>>> a = 'banana'
>>> b = 'banana'
>>> a is b
True

在这个例子中,Python只创建了一个字符串对象,并且a和b都指向它。原因是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 b
False

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

如果a指向一个对象,你赋值b = a,那么两个变量指向同一个对象:

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

参考:Allen B. Downey的《Python 2e》

Is是同一性测试,==是相等性测试。这意味着is是一种检查两件事物是否相同或等价的方法。

假设你有一个简单的person对象。如果它的名字是“Jack”,而且是“23岁”,那么它就相当于另一个23岁的Jack,但它不是同一个人。

class Person(object):
   def __init__(self, name, age):
       self.name = name
       self.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 # True
jack1 is jack2 # False

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

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

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

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

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

我相信这就是所谓的“被拘禁的”字符串。Python做到了这一点,Java也是如此,C和c++在优化模式下编译时也是如此。

如果使用两个相同的字符串,就不会因为创建两个字符串对象而浪费内存,所有具有相同内容的合并字符串都会指向相同的内存。

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

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