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
运算符的输出不一致?
答案 0 :(得分:6)
我认为它与string interning.有关。实质上,我们的想法是只存储每个不同字符串的单个副本,以提高某些操作的性能。
基本上,a is b
工作的原因是因为(正如您可能已经猜到的那样)在两种情况下都有一个由Python引用的不可变字符串。当一个字符串很大(以及其他一些我不理解的因素时,很可能),这没有完成,这就是你的第二个例子返回False的原因。
编辑:事实上,奇怪的行为似乎是交互式环境的副作用。如果您使用相同的代码并将其放入Python脚本中,则a is b
和ktr 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
请注意str
和ptr
的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的工作原理,您实际上并不知道会发生什么。 int
或float
s会遇到同样的问题。其他答案很好地解释了“幕后”的东西(字符串实习),但你在日常编程中大多不必担心它。
答案 3 :(得分:1)
请注意,这是CPython特定的优化。如果您希望代码是可移植的,则应该避免使用它。例如,在PyPy中
>>>> a = "hi"
>>>> b = "hi"
>>>> a is b
False
值得指出的是,小整数也会发生类似的事情
>>> a = 12
>>> b = 12
>>> a is b
True
这也是你不应该依赖的,因为其他实现可能不包括这种优化。