10

我了解到,在一些不可变的类中,__new__可能会返回一个现有的实例——这就是int,strtuple类型有时对小值所做的事情。

但是为什么以下两个片段的行为不同?

最后有一个空格:

>>> a = 'string '
>>> b = 'string '
>>> a is b
False

没有空格:

>>> c = 'string'
>>> d = 'string'
>>> c is d
True

为什么空间会带来差异?

4

2 回答 2

16

这是 CPython 实现如何选择缓存字符串文字的一个怪癖。具有相同内容的字符串字面量可以引用相同的字符串对象,但并非必须如此。当不是因为只包含 Python 标识符中允许的字符'string'时,碰巧会被自动实习。我不知道为什么这是他们选择的标准,但确实如此。在不同的 Python 版本或实现中,行为可能会有所不同。'string ''string'

从 CPython 2.7 源代码,stringobject.h第 28 行:

内部字符串 (ob_sstate) 试图确保只存在一个具有给定值的字符串对象,因此相等性测试可以是一个指针比较。这通常仅限于“看起来像” Python 标识符的字符串,尽管 intern() 内置函数可用于强制对任何字符串进行实习。

您可以在以下代码中看到执行此操作的代码Objects/codeobject.c

/* 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));
}

另外,请注意,实习是一个独立于 Python 字节码编译器合并字符串文字的过程。如果您让编译器将aandb赋值一起编译,例如将它们放在模块或 anif True:中,您会发现aandb将是相同的字符串。

于 2014-01-18T11:13:06.143 回答
5

这种行为并不一致,正如其他人所提到的,取决于正在执行的 Python 的变体。如需更深入的讨论,请参阅此问题

如果您想确保使用相同的对象,您可以通过适当命名的强制字符串的实习intern

实习生(...)实习生(字符串)->字符串

``Intern'' the given string.  This enters the string in the (global)
table of interned strings whose purpose is to speed up dictionary lookups.
Return the string itself or the previously interned string object with the
same value.
>>> a = 'string '
>>> b = 'string '
>>> id(a) == id(b)
False
>>> a = intern('string ')
>>> b = intern('string ')
>>> id(a) == id(b)
True

请注意,在 Python3 中,您必须显式导入 intern from sys import intern

于 2014-01-18T11:20:07.643 回答