我注意到为相同的字符串添加空格会使用is
进行比较,而非空格版本的比较相等。
a = 'abc'
b = 'abc'
a is b
#outputs: True
a = 'abc abc'
b = 'abc abc'
a is b
#outputs: False
我看过this question about comparing strings with ==
and is
。我认为这是一个不同的问题,因为空格字符正在改变行为,而不是字符串的长度。参见:
a = 'abc'
b = 'abc'
a is b # True
a = 'gfhfghssrtjyhgjdagtaerjkdhhgffdhfdah'
b = 'gfhfghssrtjyhgjdagtaerjkdhhgffdhfdah'
a is b # True
为什么在字符串中添加空格会改变此比较的结果?
答案 0 :(得分:31)
python解释器根据某些条件缓存一些字符串,第一个abc
字符串被缓存并用于两者,但第二个不是。从-5
到256
的小整数也是如此。
因为字符串是实体/缓存的,所以将a
和b
分配给"abc"
会使a
和b
指向内存中的相同对象,因此使用{ {1}},它检查两个对象是否实际上是同一个对象,返回is
。
第二个字符串True
未缓存,因此它们是内存中两个完全不同的对象,因此使用abc abc
进行身份检查会返回is
。这一次False
不 a
。它们都指向内存中的不同对象。
b
缓存字符串的条件是字符串在字符串中只有字母,下划线和数字,所以在你的情况下,空格是不符合标准。
使用解释器有一种情况,即使字符串不符合上述条件,多次分配,您也可以最终指向同一个对象。
In [43]: a = "abc" # python caches abc
In [44]: b = "abc" # it reuses the object when assigning to b
In [45]: id(a)
Out[45]: 139806825858808 # same id's, same object in memory
In [46]: id(b)
Out[46]: 139806825858808
In [47]: a = 'abc abc' # not cached
In [48]: id(a)
Out[48]: 139806688800984
In [49]: b = 'abc abc'
In [50]: id(b) # different id's different objects
Out[50]: 139806688801208
查看codeobject.c source以确定我们看到的标准In [51]: a,b = 'abc abc','abc abc'
In [52]: id(a)
Out[52]: 139806688801768
In [53]: id(b)
Out[53]: 139806688801768
In [54]: a is b
Out[54]: True
决定可以实施的内容:
NAME_CHARS
我们可以在stringobject.c来源的#define NAME_CHARS \
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
/* all_name_chars(s): true iff all chars in s are valid NAME_CHARS */
static int
all_name_chars(unsigned char *s)
{
static char ok_name_char[256];
static unsigned char *name_chars = (unsigned char *)NAME_CHARS;
if (ok_name_char[*name_chars] == 0) {
unsigned char *p;
for (p = name_chars; *p; p++)
ok_name_char[*p] = 1;
}
while (*s) {
if (ok_name_char[*s++] == 0)
return 0;
}
return 1;
}
函数中看到长度为0或1的字符串。
PyString_FromStringAndSize
与该问题没有直接关系,但对于那些感兴趣的/* share short strings */
if (size == 0) {
PyObject *t = (PyObject *)op;
PyString_InternInPlace(&t);
op = (PyStringObject *)t;
nullstring = op;
Py_INCREF(op);
} else if (size == 1 && str != NULL) {
PyObject *t = (PyObject *)op;
PyString_InternInPlace(&t);
op = (PyStringObject *)t;
characters[*str & UCHAR_MAX] = op;
Py_INCREF(op);
}
return (PyObject *) op;
}
来自PyCode_New
来源的人显示,一旦字符串符合codeobject.c
中的条件,在构建代码对象时如何实现更多字符串。
all_name_chars
这个答案基于使用cpython解释器的简单赋值,就函数或简单赋值之外的任何其他功能而言是实际的,没有被要求也没有被回答。
如果对c代码有更深入理解的人有任何可以添加的内容,请随时编辑。
整个字符串实习的解释更为全面here。