我了解到,在某些不可变类中,__new__
可能会返回一个现有实例 - 这就是int
,str
和tuple
类型有时对小值进行的操作。
但为什么以下两个片段的行为不同?
最后有一个空格:
>>> a = 'string '
>>> b = 'string '
>>> a is b
False
没有空格:
>>> c = 'string'
>>> d = 'string'
>>> c is d
True
为什么空间带来差异?
答案 0 :(得分:14)
这是CPython实现如何选择缓存字符串文字的一个怪癖。具有相同内容的字符串文字可以引用相同的字符串对象,但它们不必具有。由于'string'
不在'string '
仅包含Python标识符中允许的字符,'string'
恰好是/* 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版本或实现中,行为可能会有所不同。
从CPython 2.7源代码stringobject.h
,第28行:
实习字符串(ob_sstate)尝试确保只有一个字符串 存在给定值的对象,因此相等测试可以是一个指针 比较。这通常仅限于"看起来像" Python标识符,虽然intern()内置可以用来强制 任何字符串的实习。
您可以在Objects/codeobject.c
中看到执行此操作的代码:
a
另外,请注意,实习是与Python字节码编译器合并字符串文字的单独过程。如果让编译器一起编译b
和if True:
分配,例如通过将它们放在模块或a
中,您会发现b
和{{1}}将是相同的字符串。
答案 1 :(得分:5)
此行为不一致,正如其他人所提到的那样取决于正在执行的Python的变体。有关更深入的讨论,请参阅this question。
如果您想确定使用相同的对象,您可以通过适当命名的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中,您必须明确导入实习生from sys import intern
。