为什么在Python中 ['hello'] is ['hello'] 的结果为False?

3
3个回答

12

考虑以下内容(Python 2.7.3,64位):

>>> a = "Hello"
>>> b = "Hello"
>>> a is b
True

Python将短字符串'Hello'存储一次并进行内部引用。这是一项实现细节,不受语言标准的保证。当处理更长的字符串时可能会失败:

>>> a = "this is a long string"
>>> b = "this is a long string"
>>> a is b
False

现在考虑这个:

>>> a = ["Hello"]
>>> b = ["Hello"]
>>> a is b
False

ab 是两个不同的对象。你可以使用id()来进行检查:

>>> id(a)
33826696L
>>> id(b)
33826952L

这是一个“好事情”TM,因为当你这样做时

>>> a[0] = "Goodbye"
>>> a
['Goodbye']
>>> b
['Hello']

然而,如果您这样做

>>> a = ["Hello"]
>>> b = a
>>> a is b
True
>>> a[0] = "Goodbye"
>>> b
['Goodbye']
因为ab是指向同一对象的名称(id(a) == id(b))。最后,为了表明即使你得到了

>>> a = ["Hello"]
>>> b = ["Hello"]
>>> a is b
False

字符串仍然被池化并且只存储一次:

>>> id(a[0])
33846096L
>>> id(b[0])
33846096L

8
< p > is运算符用于测试两个对象引用是否指向同一个对象(它不是一个相等运算符,而是一个身份运算符)。在您的示例中,您创建了两个独立的列表,因此您有两个不同的对象,这就是为什么会返回False的原因。 < /p >

很好。但是我如何保证名称引用相同的对象?换句话说,我怎样才能确保我的对象进行了那种优化?为什么Python不能意识到['hello']被执行了两次? - user1730053
2
尝试将您的列表赋值给变量,这样可能会更清晰一些:l = ['hello'] l is l将返回True,l = ['hello'] m = ['hello'] l is m将返回False。 - codebox
如果你这么写:a = ['hello']; b = ['hello'],那么a is b会返回False,因为它们是两个不同的对象。毕竟,你不希望对a[0] = "Goodbye"的修改影响到b吧?但是,如果你这么写:a = ['hello']; b = a,那么a is b会返回True,并且对a[0] = "Goodbye"的修改也会影响到b - Tim Pietzcker
@TimPietzcker 那么,可变对象是不是导致 Python 不对其进行优化(作为一项政策决定)的原因? - user1730053
3
无需优化——您有两个不同且独立的对象。字符串'hello'通过驻留已经被优化,因此仅存储一次。但是您的is比较并不比较字符串,而是比较列表! - Tim Pietzcker

1

当您使用[]语法创建列表时,将创建一个新的列表对象。列表是可变对象,因此,即使两个列表恰好包含相同的元素,它们也不是相同的对象。您可以观察到通过调用其修改方法之一来更改列表实际上并不会更改ID:

In [1]: a = ["hello"]
In [2]: b = ["hello"]
In [3]: id(a)
Out[3]: 4477468112
In [4]: id(b)
Out[4]: 4477467824
In [5]: a.append("world")
In [6]: id(a)
Out[6]: 4477468112

“对于不可变对象,例如字符串,不同的变量实际上将引用不同的对象”是不正确的。请参见Tim Pietzcker在此问题上的回答。 - phant0m
是的,谢谢提示。我已经删除了那一部分。 - silvado

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接