首页 文章

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

提问于
浏览
939

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

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

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

我在这里想念的是什么?

15 回答

  • 469

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

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

    From Language Reference:

    类型几乎影响对象行为的所有方面 . 甚至对象身份的重要性在某种意义上也会受到影响:对于不可变类型,操作 that compute new values may actually return a reference to any existing object with the same type and value, while for mutable objects this is not allowed . 例如,在a = 1之后; b = 1,a和b可能会或可能不会引用具有值1的同一对象,具体取决于实现,但在c = []之后; d = [],c和d保证引用两个不同的,唯一的,新创建的空列表 . (注意c = d = []将同一个对象分配给c和d . )

    所以从上面的语句我们可以推断,当用“is”检查时,不可变类型的字符串可能会失败,并且当用“is”检查时可能检查成功

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

  • 1301

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

    如果使用 is ,则当且仅当对象是同一对象时,结果才为真 . 但是,只要对象的值相同, == 将为true .

  • 30

    如果您不确定自己在做什么,请使用'==' . 如果您对此有更多的了解,可以使用'is'作为'None'等已知对象 .

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

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

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

  • 24

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

    if x is None: 
        # some clauses
    

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

  • 11

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

    == 将比较程序中的变量 . 它用于检查 Value 水平 .

    is 检查地址级别等效性

    == 检查 Value 水平等值

  • 15

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

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

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

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

  • 9

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

    这是一个很好的例子:

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

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

  • 51

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

  • 33

    == 运算符测试值等价 . 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
    
  • 16

    is 是身份测试, == 是相等测试 . 这是什么意思是 is 是一种检查两件事物是相同的东西,还是只是等价物的方法 .

    假设你有一个简单的 person 对象 . 如果它被命名为'Jack'并且是'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
    

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

  • 96

    而是尝试使用

    s1='public'
    s2='public'
    sorted(s1) == sorted(s2)
    

    上面的代码会给出 TRUE 的结果

    s1='public'
    s2='publci'
    sorted(s1) == sorted(s2)
    

    上面的代码会给出 TRUE 的结果

    s1='public'
    s2='publca'
    sorted(s1) == sorted(s2)
    

    上面的代码会给出结果 FALSE

  • -1

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

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

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

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

  • 1

    is 是身份测试, == 是相等测试(参见Python Documentation) .

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

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

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

  • 4

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

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

    Interned字符串加速字符串比较,这有时是应用程序(例如编译器和动态编程语言运行时)的性能瓶颈,这些应用程序严重依赖于带有字符串键的哈希表 . 没有实习,检查两个不同的字符串是否相等涉及检查两个字符串的每个字符 . 由于以下几个原因,这很慢:它本身就是字符串长度的O(n);它通常需要从几个内存区域读取,这需要时间;并且读取将填满处理器缓存,这意味着可用于其他需求的缓存更少 . 对于实习字符串,在原始实习操作之后,简单的对象标识测试就足够了;这通常实现为指针相等测试,通常只是一个没有内存引用的机器指令 .

    因此,当您在程序中有两个字符串文字(字面上键入您的程序源代码,用引号括起来)时,Python编译器会自动生成字符串,使它们都存储在同一个字符串中记忆位置 . (请注意,这并不总是发生,并且发生这种情况的规则非常复杂,因此请不要在 生产环境 代码中依赖此行为!)

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

  • 0

    我相信这被称为“实习”字符串 . Python就是这样做的,Java也是如此,在优化模式下进行编译时也是如此 .

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

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

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

相关问题