Why does a space affect the identity comparison of equal strings?
我注意到,使用
1 2 3 4 5 6 7 8 9 | a = 'abc' b = 'abc' a is b #outputs: True a = 'abc abc' b = 'abc abc' a is b #outputs: False |
我读过这个关于比较字符串与
1 2 3 4 5 6 7 | a = 'abc' b = 'abc' a is b # True a = 'gfhfghssrtjyhgjdagtaerjkdhhgffdhfdah' b = 'gfhfghssrtjyhgjdagtaerjkdhhgffdhfdah' a is b # True |
为什么在字符串中添加空格会更改此比较的结果?
python解释器根据某些条件缓存一些字符串,第一个
由于字符串被截取/缓存,将
第二个字符串
1 2 3 4 5 6 7 8 9 10 11 12 | 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 |
缓存字符串的条件是,如果字符串中只有字母、下划线和数字,那么在这种情况下,空间不符合条件。
使用解释器,有一种情况下,即使字符串不符合上述条件,也可以指向同一对象,即多次赋值。
1 2 3 4 5 6 7 8 9 10 | 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 |
寻找codeobject.c源来决定我们看到的标准
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #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的字符串将始终共享,正如我们在stringobject.c源中的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /* 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; } |
不直接与问题有关,但对于那些感兴趣的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | PyCodeObject * PyCode_New(int argcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, int firstlineno, PyObject *lnotab) { PyCodeObject *co; Py_ssize_t i; /* Check argument types */ if (argcount < 0 || nlocals < 0 || code == NULL || consts == NULL || !PyTuple_Check(consts) || names == NULL || !PyTuple_Check(names) || varnames == NULL || !PyTuple_Check(varnames) || freevars == NULL || !PyTuple_Check(freevars) || cellvars == NULL || !PyTuple_Check(cellvars) || name == NULL || !PyString_Check(name) || filename == NULL || !PyString_Check(filename) || lnotab == NULL || !PyString_Check(lnotab) || !PyObject_CheckReadBuffer(code)) { PyErr_BadInternalCall(); return NULL; } intern_strings(names); intern_strings(varnames); intern_strings(freevars); intern_strings(cellvars); /* Intern selected string constants */ for (i = PyTuple_Size(consts); --i >= 0; ) { PyObject *v = PyTuple_GetItem(consts, i); if (!PyString_Check(v)) continue; if (!all_name_chars((unsigned char *)PyString_AS_STRING(v))) continue; PyString_InternInPlace(&PyTuple_GET_ITEM(consts, i)); } |
这个答案是基于使用cpython解释器的简单赋值,就函数或简单赋值之外的任何其他功能而言,这是没有被询问或回答的。
如果任何对C代码有更深入理解的人有什么需要添加的,请随意编辑。
这里有一个更彻底的解释,整个弦乐节间。