1265

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

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

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

我在这里想念什么?

4

15 回答 15

1637

is是身份测试,==是平等测试。您的代码中发生的事情将在解释器中模拟,如下所示:

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

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

换句话说:a is b相当于id(a) == id(b)

于 2009-10-01T15:45:20.020 回答
630

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

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

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

因此,当您的程序中有两个具有相同值的字符串文字(字面上键入到程序源代码中的单词,用引号括起来)时,Python 编译器将自动对字符串进行内部处理,使它们都存储在相同的位置内存位置。(请注意,这并不总是发生,发生这种情况的规则非常复杂,所以请不要在生产代码中依赖这种行为!)

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

于 2009-10-01T16:02:14.637 回答
117

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

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

于 2009-10-01T15:45:02.057 回答
62

最后要注意的是,您可以使用该sys.intern函数来确保您获得对相同字符串的引用:

>>> from sys import intern
>>> a = intern('a')
>>> a2 = intern('a')
>>> a is a2
True

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

请注意,该intern函数曾经是 Python 2 上的内置函数,但在 Python 3 中被移至sys模块中。

于 2009-10-01T16:04:48.907 回答
48

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

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

于 2013-04-29T00:56:52.640 回答
39

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

if x is None:
    # Some clauses

这是安全的,因为保证有一个 Null Object (ie, None) 的实例

于 2009-10-01T18:51:32.120 回答
32

如果您不确定自己在做什么,请使用“==”。如果您对此有更多了解,您可以将“is”用于已知对象,例如“None”。

否则,您最终会想知道为什么事情不起作用以及为什么会发生这种情况:

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

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

于 2009-10-01T16:57:09.930 回答
24

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

这是一个很好的例子:

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

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

于 2009-10-01T15:48:07.667 回答
20

我认为这与以下事实有关,即当“is”比较评估为假时,使用了两个不同的对象。如果它评估为真,这意味着它在内部使用相同的确切对象而不是创建新对象,可能是因为您在 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',如果我有它会使它们成为同一个对象。

于 2009-10-01T15:45:07.487 回答
15

我相信这被称为“实习”字符串。在优化模式下编译时,Python 会这样做,Java 也会这样做,C 和 C++ 也会这样做。

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

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

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

于 2009-10-01T15:59:38.653 回答
14

实际上,is运算符检查身份, == 运算符检查相等性。

从语言参考:

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

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

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

于 2014-08-08T17:04:58.627 回答
13

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

>>> 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
于 2017-07-05T04:59:32.280 回答
7

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

==将比较程序中的变量。它用于在值级别进行检查。

is检查地址级别等价性

==检查价值水平等价

于 2017-09-14T20:27:43.400 回答
2

is是身份测试并且==是相等测试(请参阅Python 文档)。

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

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

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

于 2017-04-24T11:37:33.460 回答
-2

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

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

所以,我们可以说它用于比较内存位置。然而,

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

代码

点击这里获取代码

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

于 2020-12-26T16:31:42.433 回答