为什么在Python中使用'=='或'is'比较string有时会产生不同的结果?
我有一个Python程序,其中两个variables设置为'public'
值。 在条件expression式我有比较var1 is var2
失败,但如果我将其更改为var1 == var2
它将返回True
。
现在,如果我打开我的Python解释器,并做相同的“是”比较,它会成功。
>>> s1 = 'public' >>> s2 = 'public' >>> s2 is s1 True
我在这里错过了什么?
is
身份testing, ==
是平等testing。 在你的代码中会发生什么,将会在解释器中被仿效:
>>> a = 'pub' >>> b = ''.join(['p', 'u', 'b']) >>> a == b True >>> a is b False
所以,难怪他们不一样,对吧?
换句话说: is
id(a) == id(b)
SilentGhost和其他人在这里是正确的。 is
用于标识比较,而==
用于相等比较。
交互式工作的原因是(大多数)string文字是默认实现的。 维基百科:
Internedstring加快了string比较的速度,这在有很大程度上依赖于带有string键的散列表的应用程序(例如编译器和dynamic编程语言运行时)中是性能瓶颈。 没有实习,检查两个不同的string是否相等涉及检查两个string的每个字符。 由于几个原因,这是很慢的:它在string长度上本质上是O(n); 它通常需要从几个内存区域读取,这需要花费时间; 并且读取填满了处理器caching,这意味着caching可用于其他需求。 使用internedstring,在原始实习操作之后,一个简单的对象身份testing就足够了; 这通常是作为一个指针相等testing来实现的,通常只是一个没有内存引用的机器指令。
所以,当你的程序中有两个string文字(字面types为程序源代码的文字,用引号括起来),Python编译器会自动实习string,使它们都存储在相同的内存位置。 (请注意,这并不总是会发生,而且发生这种情况的规则是相当复杂的,所以请不要在生产代码中依赖这种行为!)
由于在交互式会话中,两个string实际上存储在同一个内存位置,它们具有相同的标识 ,因此is
运算符按预期工作。 但是如果通过其他方法构造一个string(即使该string包含完全相同的字符),那么该string可能是相等的 ,但它不是相同的string – 也就是说,它具有不同的身份 ,因为它是存储在内存中的一个不同的地方。
is
关键字是对象身份的testing,而==
是值的比较。
如果使用is
,则当且仅当该对象是同一个对象时,结果才为真。 但是,每当对象的值相同时, ==
都是正确的。
最后要注意的是,你可以使用intern函数来确保你得到了对同一个string的引用:
>>> a = intern('a') >>> a2 = intern('a') >>> a is a2 True
如上所述,你可能不应该做的是确定string的平等。 但是,这可能有助于知道你是否有某种奇怪的要求使用。
请注意,Intern函数已经从一个内置函数移动到了Python 3的模块sys
中。
这是一个方面的说明,但在惯用python,你会经常看到的东西,如:
if x is None: # some clauses
这是安全的,因为保证有一个空对象的实例(即无) 。
is
身份testing, ==
是平等testing。 这意味着这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
他们是同一个年龄段,但他们不是同一个人。 一个string可能相当于另一个,但它不是同一个对象。
如果您不确定自己在做什么,请使用“==”。 如果你对它有更多的了解,你可以使用“is”来表示已知的对象,比如“None”。
否则,你会最终想知道为什么事情不起作用,为什么会发生这种情况:
>>> a = 1 >>> b = 1 >>> b is a True >>> a = 6000 >>> b = 6000 >>> b is a False
我甚至不确定是否有一些事情保证在不同的Python版本/实现之间保持不变。
从我有限的python经验, is
用来比较两个对象,看看他们是相同的对象,而不是两个不同的对象具有相同的值。 ==
用于确定值是否相同。
这是一个很好的例子:
>>> s1 = u'public' >>> s2 = 'public' >>> s1 is s2 False >>> s1 == s2 True
s1
是一个Unicodestring,而s2
是一个普通的string。 他们不是一样的types,但价值相同。
我认为这与事实有关,当“是”比较评估为错误时,使用两个不同的对象。 如果评估结果为真,那意味着它在内部使用相同的确切对象,而不是创build一个新的对象,可能是因为您创build它们的时间在2秒或更短的时间内,而且它们之间没有很大的时间差使用相同的对象。
这就是为什么你应该使用相等运算符==
,而不是比较string对象的值。
>>> s = 'one' >>> s2 = 'two' >>> s is s2 False >>> s2 = s2.replace('two', 'one') >>> s2 'one' >>> s2 is s False >>>
在这个例子中,我做了s2,它是一个不同的string对象,以前等于'one',但它不是与s
相同的对象,因为解释器没有使用相同的对象,因为我最初并没有将它分配给'one' ,如果我有了,它会使他们成为同一个对象。
我相信这被称为“interned”string。 Python是这样做的,Java也是如此,在优化模式下编译时,C和C ++也是如此。
如果使用两个相同的string,而不是通过创build两个string对象来浪费内存,则具有相同内容的所有string指向相同的内存。
这导致Python的“is”操作符返回True,因为具有相同内容的两个string指向相同的string对象。 这也会发生在Java和C中
这只对节省内存很有用。 你不能依赖它来testingstring的平等,因为各种解释器和编译器和JIT引擎不能总是这样做。
我正在回答这个问题,即使问题是老的,因为没有上面的答案引用语言参考
其实是运算符检查身份和==运算符检查是否相等,
来自语言参考:
types几乎影响对象行为的所有方面。 即使对象身份的重要性在某种意义上也受到了影响:对于不可变types, 计算新值的操作实际上可能会返回对具有相同types和值的任何现有对象的引用,而对于可变对象则不允许 。 例如,a = 1之后; b = 1,a和b可能或不可能引用与值1相同的对象,具体取决于实现,但在c = []之后; d = [],c和d保证引用两个不同的唯一的新创build的空列表。 (请注意,c = d = []将同一个对象分配给c和d)。
所以从上面的语句中,我们可以推断,当使用“is”进行检查时,不可变types的string可能会失败,并且在使用“is”进行检查时可能会检查成功。
这也适用于int,也是不可变types的元组
is
身份testing, ==
是平等testing(请参阅Python文档 )。
在大多数情况下,如果a is b
,那么a == b
。 但也有例外,例如:
>>> nan = float('nan') >>> nan is nan True >>> nan == nan False
所以,你只能使用身份testing,而不能进行平等testing。
==
运算符testing值相等。 is
运算符testing对象标识,Pythontesting这两个是否真的是同一个对象(即,存在于内存中相同的地址)。
>>> a = 'banana' >>> b = 'banana' >>> a is b True
在这个例子中,Python只创build了一个string对象, a
和b
指向它。 原因是Python内部caching和重用了一些string作为优化,实际上只是一个string“香蕉”在内存中,由a和b共享; 要触发正常的行为,你需要使用更长的string:
>>> a = 'a longer banana' >>> b = 'a longer banana' >>> a == b, a is b (True, False)
当你创build两个列表时,你会得到两个对象:
>>> a = [1, 2, 3] >>> b = [1, 2, 3] >>> a is b False
在这种情况下,我们可以说这两个列表是等价的,因为它们具有相同的元素,但不完全相同,因为它们不是同一个对象。 如果两个对象是相同的,它们也是等价的,但是如果它们是等价的,它们不一定是相同的。
如果a
引用了一个对象并且赋值b = a
,那么这两个variables都引用同一个对象:
>>> a = [1, 2, 3] >>> b = a >>> b is a True
is
会比较内存的位置。 它用于对象级比较。
==
会比较程序中的variables。 它用于检查价值水平。
is
检查地址级别等价
==
检查值级别等价