对字符串的`is`操作符感到困惑

时间:2012-10-25 05:28:31

标签: python string

is运算符比较两个对象的内存地址,如果它们相同则返回True。那么,为什么它不能可靠地使用字符串? 代码#1

>>> a = "poi"
>>> b = "poi"
>>> a is b
True

代码#2

>>> ktr = "today is a fine day"
>>> ptr = "today is a fine day"
>>> ktr is ptr
False

我创建了两个字符串,其内容相同,但它们位于不同的内存地址上。为什么is运算符的输出不一致?

4 个答案:

答案 0 :(得分:6)

我认为它与string interning.有关。实质上,我们的想法是只存储每个不同字符串的单个副本,以提高某些操作的性能。

基本上,a is b工作的原因是因为(正如您可能已经猜到的那样)在两种情况下都有一个由Python引用的不可变字符串。当一个字符串很大(以及其他一些我不理解的因素时,很可能),这没有完成,这就是你的第二个例子返回False的原因。

编辑:事实上,奇怪的行为似乎是交互式环境的副作用。如果您使用相同的代码并将其放入Python脚本中,则a is bktr is ptr都将返回True。

a="poi"
b="poi"
print a is b  # Prints 'True'

ktr = "today is a fine day"
ptr = "today is a fine day"
print ktr is ptr  # Prints 'True'

这是有道理的,因为Python很容易解析源文件并在其中查找重复的字符串文字。如果您动态创建字符串,那么即使在脚本中它也会有不同的行为。

a="p" + "oi"
b="po" + "i"
print a is b  # Oddly enough, prints 'True'

ktr = "today is" + " a fine day"
ptr = "today is a f" + "ine day"
print ktr is ptr  # Prints 'False'

至于为什么a is b仍然导致True,或许分配的字符串足够小以保证快速搜索实习集合,而另一个不是?

答案 1 :(得分:3)

is是身份测试。它将在较小的某些字符串(因为缓存)上工作,但不能在更大的其他字符串上工作。因为str不是ptr。 [感谢erykson]

请参阅此代码:

>>> import dis
>>> def fun():
...   str = 'today is a fine day'
...   ptr = 'today is a fine day'
...   return (str is ptr)
...
>>> dis.dis(fun)
  2           0 LOAD_CONST               1 ('today is a fine day')
              3 STORE_FAST               0 (str)

  3           6 LOAD_CONST               1 ('today is a fine day')
              9 STORE_FAST               1 (ptr)

  4          12 LOAD_FAST                0 (str)
             15 LOAD_FAST                1 (ptr)
             18 COMPARE_OP               8 (is)
             21 RETURN_VALUE

>>> id(str)
26652288
>>> id(ptr)
27604736
#hence this comparison returns false: ptr is str

请注意strptr的ID不同。

BUT:

>>> x = "poi"
>>> y = "poi"
>>> id(x)
26650592
>>> id(y)
26650592
#hence this comparison returns true : x is y

x和y的ID相同。因此is运算符适用于“ids”而非“均等”

有关python何时以及为何为相同字符串分配不同内存位置的讨论,请参阅以下链接(同时阅读该问题)。

When does python allocate new memory for identical strings

python3.x上的sys.intern和python2.x上的intern也可以帮助您在相同的内存位置分配字符串,而不管字符串的大小。

答案 2 :(得分:2)

is ==相同。

基本上,is检查两个对象是否相同,而==比较这些对象的值(字符串,如python中的所有内容,都是对象)。

所以你应该在你真正知道你正在看什么对象时使用is(即你已经制作了这些对象,或者正如问题评论指出的那样与None进行比较),并且您想知道两个变量是否在内存中引用完全相同的对象

但是,在您的示例中,您正在查看python正在幕后处理的str个对象,因此,如果不深入了解python的工作原理,您实际上并不知道会发生什么。 intfloat s会遇到同样的问题。其他答案很好地解释了“幕后”的东西(字符串实习),但你在日常编程中大多不必担心它。

答案 3 :(得分:1)

请注意,这是CPython特定的优化。如果您希望代码是可移植的,则应该避免使用它。例如,在PyPy中

>>>> a = "hi"
>>>> b = "hi"
>>>> a is b
False

值得指出的是,小整数也会发生类似的事情

>>> a = 12
>>> b = 12
>>> a is b
True

这也是你不应该依赖的,因为其他实现可能不包括这种优化。

相关问题