比较字符串和空格时,“ is”运算符的行为有所不同


问题内容

我已经开始学习Python(python 3.3),并且正在尝试该is运算符。我尝试了这个:

>>> b = 'is it the space?'
>>> a = 'is it the space?'
>>> a is b
False
>>> c = 'isitthespace'
>>> d = 'isitthespace'
>>> c is d
True
>>> e = 'isitthespace?'
>>> f = 'isitthespace?'
>>> e is f
False

似乎空格和问号使is行为有所不同。这是怎么回事?

编辑: 我知道我应该使用==,我只是想知道为什么is会这样。


问题答案:

警告:此答案是关于特定python解释器的实现细节的。 比较带有is==坏主意的字符串。

好吧,至少对于cpython3.4 / 2.7.3,答案是“不,它不是空格”。不 只是 空白:

  • 如果两个字符串文字是字母数字或位于同 一块 (文件,函数,类或单个解释器命令),则它们将共享内存。

  • 如果且仅当使用常量和二进制/一元运算符创建了一个表达式,并且该表达式的字符串少于21个字符时,该表达式才能得出与字符串文本相同的对象。

  • 单个字符是唯一的。

例子

字母数字字符串文字始终共享内存:

>>> x='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
>>> y='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
>>> x is y
True

非字母数字字符串文字在且仅当它们共享封闭的语法块时才共享内存:

(口译员)

>>> x='`!@#$%^&*() \][=-. >:"?<a'; y='`!@#$%^&*() \][=-. >:"?<a';
>>> z='`!@#$%^&*() \][=-. >:"?<a';
>>> x is y
True 
>>> x is z
False

(文件)

x='`!@#$%^&*() \][=-. >:"?<a';
y='`!@#$%^&*() \][=-. >:"?<a';
z=(lambda : '`!@#$%^&*() \][=-. >:"?<a')()
print(x is y)
print(x is z)

输出:TrueFalse

对于简单的二进制操作,编译器将执行非常简单的常量传播(请参阅peephole.c),但是对于字符串,仅当结果字符串小于21个字符时,才这样做。在这种情况下,前面提到的规则将生效:

>>> 'a'*10+'a'*10 is 'a'*20
True
>>> 'a'*21 is 'a'*21
False
>>> 'aaaaaaaaaaaaaaaaaaaaa' is 'aaaaaaaa' + 'aaaaaaaaaaaaa'
False
>>> t=2; 'a'*t is 'aa'
False
>>> 'a'.__add__('a') is 'aa'
False
>>> x='a' ; x+='a'; x is 'aa'
False

当然,单个字符始终共享内存:

>>> chr(0x20) is ' '
True