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

时间:2009-10-01 15:40:15

标签: python string comparison identity equality

我有一个Python程序,其中两个变量设置为值'public'。在条件表达式中,我将比较var1 is var2失败,但如果我将其更改为var1 == var2,则会返回True

现在,如果我打开我的Python解释器并进行相同的“是”比较,它就会成功。

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

我在这里缺少什么?

15 个答案:

答案 0 :(得分:1387)

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

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

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

换句话说:isid(a) == id(b)

答案 1 :(得分:509)

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

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

  

Interned字符串加速字符串   比较,有时是一个   应用程序中的性能瓶颈   (比如编译器和动态   编程语言运行时)   严重依赖哈希表   字符串键。没有实习,   检查两个不同的字符串   是平等的涉及检查每一个   两个字符串的字符。这是   缓慢有几个原因:它是   本质上是O(n)的长度   串;它通常需要读取   来自几个记忆区域,其中   慢慢来;并且读取填满了   处理器缓存,意味着更少   缓存可用于其他需求。同   实习字符串,一个简单的对象   身份测试后就足够了   原来的实习生;这是   通常实现为指针   平等测试,通常只是一个单一的   没有记忆的机器指令   参考。

因此,如果你的程序中有两个字符串文字(字面上输入你的程序源代码,用引号括起来),它们具有相同的值,那么Python编译器会自动实际输入字符串,使它们都存储起来在相同的内存位置。 (请注意,这不会发生始终,并且发生这种情况的规则非常复杂,因此请不要在生产代码中依赖此行为!)

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

答案 2 :(得分:100)

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

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

答案 3 :(得分:54)

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

>>> a = intern('a')
>>> a2 = intern('a')
>>> a is a2
True

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

请注意,实习函数已从内置函数转移到Python 3的模块sys中。

答案 4 :(得分:37)

is是身份测试,==是相等测试。这意味着is是一种检查两个事物是相同事物还是等价物的方法。

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

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

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

答案 5 :(得分:34)

这是一个旁注,但在惯用的python中,你经常会看到如下内容:

if x is None: 
    # some clauses

这是安全的,因为there is guaranteed to be one instance of the Null Object (i.e., None)

答案 6 :(得分:26)

如果您不确定自己在做什么,请使用'=='。 如果你对它有更多的了解,你可以使用'is'来表示'None'这样的已知对象。

否则你最终会想知道为什么事情不起作用以及为什么会这样:

>>> a = 1
>>> b = 1
>>> b is a
True
>>> a = 6000
>>> b = 6000
>>> b is a
False

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

答案 7 :(得分:19)

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

这是一个很好的例子:

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

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

答案 8 :(得分:16)

我认为这与以下事实有关:当'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',如果我拥有它会使它们成为同一个对象。

答案 9 :(得分:12)

我相信这被称为“实习”字符串。 Python可以做到这一点,Java也是如此,在优化模式下进行编译时,C和C ++也是如此。

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

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

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

答案 10 :(得分:10)

我正在回答这个问题,即使这个问题已经过时了,因为上述答案没有引用语言参考

实际上是运算符检查标识和==运算符检查是否相等,

来自语言参考:

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

所以从上面的语句我们可以推断出,当用""检查时,不可变类型的字符串可能会失败。在使用""

进行检查时可以检查成功

同样适用于int,tuple,它们也是不可变类型

答案 11 :(得分:6)

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

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

在此示例中,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 b
False

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

如果a引用了一个对象,并且您指定了b = a,则两个变量都引用同一个对象:

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

答案 12 :(得分:2)

is是身份测试,==是相等测试(请参阅Python Documentation)。

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

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

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

答案 13 :(得分:2)

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

==将比较程序中的变量。它用于检查价值水平。

is检查地址级别等效性

==检查价值水平等值

答案 14 :(得分:-2)

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

<块引用>

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

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

<块引用>

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

代码

Click here for the code

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