提问人:jottos 提问时间:10/1/2009 最后编辑:Mateen Ulhaqjottos 更新时间:1/26/2023 访问量:1650711
为什么使用“==”或“is”比较字符串有时会产生不同的结果?
Why does comparing strings using either '==' or 'is' sometimes produce a different result?
问:
两个字符串变量设置为相同的值。 总是返回 ,但有时返回 。s1 == s2
True
s1 is s2
False
如果我打开我的 Python 解释器并进行相同的比较,它会成功:is
>>> s1 = 'text'
>>> s2 = 'text'
>>> s1 is s2
True
为什么会这样?
答:
关键字是对对象标识的测试,而是值比较。is
==
如果使用 ,则当且仅当对象是同一对象时,结果才会为 true。但是,只要对象的值相同,就会为 true。is
==
我认为这与以下事实有关:当“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',但它与 不是同一个对象,因为解释器没有使用相同的对象,因为我最初没有将其分配给 'one',如果我有它,它们会成为同一个对象。s
评论
.replace()
s2 = s2.replace()
s2
s2
s = s.replace('one', 'one')
is
是身份测试,也是平等测试。代码中发生的情况将在解释器中模拟,如下所示:==
>>> a = 'pub'
>>> b = ''.join(['p', 'u', 'b'])
>>> a == b
True
>>> a is b
False
所以,难怪它们不一样,对吧?
换言之:等价于a is b
id(a) == id(b)
评论
==
.equals()
==
==
None
根据我对 Python 的有限经验,用于比较两个对象,看看它们是否是同一个对象,而不是两个具有相同值的不同对象。 用于确定值是否相同。is
==
下面是一个很好的例子:
>>> s1 = u'public'
>>> s2 = 'public'
>>> s1 is s2
False
>>> s1 == s2
True
s1
是 Unicode 字符串,并且是普通字符串。它们不是同一类型,但它们是相同的值。s2
评论
<type 'unicode'>
<type 'str'>
s1
str
is
==
True
我认为这被称为“interned”字符串。Python这样做,Java也是如此,在优化模式下编译时,C和C++也是如此。
如果使用两个相同的字符串,则所有具有相同内容的内部字符串都指向同一内存,而不是通过创建两个字符串对象来浪费内存。
这会导致 Python“is”运算符返回 True,因为两个具有相同内容的字符串指向同一个字符串对象。这也将发生在 Java 和 C 中。
不过,这仅对节省内存有用。你不能依赖它来测试字符串是否相等,因为各种解释器和编译器以及 JIT 引擎不能总是这样做。
评论
这里的其他答案是正确的:用于同一性比较,而用于平等比较。由于您关心的是相等性(两个字符串应包含相同的字符),在这种情况下,运算符是错误的,您应该改用。is
==
is
==
以交互方式工作的原因是(大多数)字符串文字默认是内部的。来自维基百科:is
被隔离的字符串加速字符串 比较,有时是 应用程序中的性能瓶颈 (例如编译器和动态 编程语言运行时),即 严重依赖哈希表 字符串键。无需实习, 检查两个不同的字符串 是平等的,涉及检查每一个 两个字符串的字符。这是 慢有几个原因:它是 固有的 O(n) 的长度 字符串;它通常需要读取 从几个内存区域,其中 花点时间;并且读取填满了 处理器缓存,意味着更少 缓存可用于其他需求。跟 interned strings,一个简单的对象 在 原实习生操作;这是 通常作为指针实现 相等性测试,通常只是一个 无记忆的机器指令 完全参考。
因此,当程序中有两个具有相同值的字符串文字(字面上键入到程序源代码中的单词,用引号括起来)时,Python 编译器将自动插入字符串,使它们都存储在相同的内存位置。(请注意,这并不总是发生,而且发生这种情况的规则非常复杂,因此请不要在生产代码中依赖此行为!
由于在交互式会话中,两个字符串实际上都存储在相同的内存位置,因此它们具有相同的标识,因此运算符按预期工作。但是,如果你用其他方法构造一个字符串(即使该字符串包含完全相同的字符),那么这个字符串可能是相等的,但它不是同一个字符串——也就是说,它具有不同的身份,因为它存储在内存中的不同位置。is
评论
==
is
==
is
is
==
最后要注意的是,您可以使用 sys.intern
函数来确保获得对同一字符串的引用:
>>> from sys import intern
>>> a = intern('a')
>>> a2 = intern('a')
>>> a is a2
True
正如前面的答案所指出的,你不应该用来确定字符串的相等性。但这可能有助于了解您是否有某种奇怪的要求。is
is
请注意,该函数曾经是 Python 2 上的内置函数,但它已移至 Python 3 中的模块。intern
sys
如果您不确定自己在做什么,请使用“==”。 如果你对它有更多的了解,你可以使用“is”来表示已知对象,如“None”。
否则,您最终会想知道为什么事情不起作用以及为什么会发生这种情况:
>>> a = 1
>>> b = 1
>>> b is a
True
>>> a = 6000
>>> b = 6000
>>> b is a
False
我什至不确定某些东西是否保证在不同的 Python 版本/实现之间保持不变。
评论
这是一个旁注,但在惯用的 Python 中,您经常会看到以下内容:
if x is None:
# Some clauses
这是安全的,因为保证有一个 Null 对象实例(即 None)。
评论
is
是身份测试,也是平等测试。这意味着一种检查两件事是相同还是等价的方法。==
is
假设你有一个简单的对象。如果它的名字是“杰克”,并且是“23”岁,它相当于另一个23岁的杰克,但它不是同一个人。person
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
他们是同龄人,但他们不是同一个人。一个字符串可能等同于另一个字符串,但它不是同一个对象。
评论
jack1.age = 99
jack2.age
jack1 is not jack2
jack1 == jack2
实际上,运算符检查标识,== 运算符检查是否相等。is
从语言参考:
类型几乎影响对象行为的所有方面。甚至对象标识的重要性在某种意义上也会受到影响:对于不可变类型,计算新值的操作实际上可能会返回对具有相同类型和值的任何现有对象的引用,而对于可变对象,这是不允许的。例如,在 a = 1 之后;b = 1,a 和 b 可能引用值为 1 的同一对象,也可能不引用,具体取决于实现,但在 c = [] 之后;d = [],c 和 d 保证引用两个不同的、唯一的、新创建的空列表。(请注意,c = d = [] 将相同的对象分配给 c 和 d。
因此,从上面的语句中我们可以推断出,字符串是不可变类型,当用“is”检查时可能会失败,而当用“is”检查时可能会成功。
这同样适用于 和 它们也是不可变的类型。int
tuple
is
是身份测试,也是相等性测试(请参阅 Python 文档)。==
在大多数情况下,如果 ,则 .但也有例外,例如:a is b
a == b
>>> nan = float('nan')
>>> nan is nan
True
>>> nan == nan
False
因此,您只能用于身份测试,而不能用于相等性测试。is
运算符测试值等效性。运算符测试对象身份,Python 测试两者是否真的是同一个对象(即,位于内存中的同一地址)。==
is
>>> a = 'banana'
>>> b = 'banana'
>>> a is b
True
在此示例中,Python 只创建了一个字符串对象,并且都引用了 and。原因是 Python 在内部缓存并重用一些字符串作为优化。内存中实际上只有一个字符串“banana”,由 a 和 b 共享。若要触发正常行为,需要使用更长的字符串: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
参考资料:Think Python 2e,作者:Allen B. Downey
评论
is
将比较内存位置。它用于对象级比较。
==
将比较程序中的变量。它用于在值级别进行检查。
is
检查地址级别的等效性
==
检查值级别等效性
在处理这个问题时,我们必须清楚的基本概念是理解 is 和 == 之间的区别。
“is”是将比较内存位置。如果 id(a)==id(b),则 a 是 b 返回 true,否则返回 false。
因此,我们可以说这是用于比较内存位置的。而
==用于相等性测试,这意味着它只比较结果值。下面显示的代码可以作为上述给定理论的示例。
法典
对于字符串文字(未分配给变量的字符串),内存地址将与图中所示相同。所以,id(a)==id(b)。剩下的就是不言自明的。
评论
input = raw_input("Decide (y/n): ")
if input == 'y':
if input is 'y':