字符串 split() 的身份怪癖
Identity quirk with string split()
>>> 'hi'.split()[0] is 'hi'
True
>>> 'hi there'.split()[0] is 'hi'
False
>>> 'hi there again'.split()[0] is 'hi'
False
我的假设:
第一行split只有一个元素,其他两行有多个元素。我相信,虽然像 str
这样的 Python 基元在函数中按值存储在内存中,但函数之间将有单独的分配以简化内存管理。我认为 split()
是其中一个函数,它通常会分配新的字符串。但它也处理不需要任何拆分的输入的边缘情况(例如 'hi'
),其中只返回原始字符串引用。我的解释正确吗?
正如我在评论中所说:
'hi there again'.split()[0] == 'hi'
>>True
实际上你的问题有点一针见血 - 这是一个身份。
I believe that while Python primitives like str are stored in memory by value within a function, there will be separate allocations across functions to simplify memory management.
Python 的对象分配不会那样工作。 "primitives" 没有一个真正的概念,除了字节码编译器为合并常量所做的一些事情之外,两个对象是在同一个函数中创建还是在不同函数中创建并不重要。
没有比指出来源更好的答案了,所以 here it is:
Py_LOCAL_INLINE(PyObject *)
STRINGLIB(split_whitespace)(PyObject* str_obj,
const STRINGLIB_CHAR* str, Py_ssize_t str_len,
Py_ssize_t maxcount)
{
...
#ifndef STRINGLIB_MUTABLE
if (j == 0 && i == str_len && STRINGLIB_CHECK_EXACT(str_obj)) {
/* No whitespace in str_obj, so just use it as list[0] */
Py_INCREF(str_obj);
PyList_SET_ITEM(list, 0, (PyObject *)str_obj);
count++;
break;
}
如果它没有找到任何可拆分的空格,它只会重复使用返回列表中的原始字符串对象。这只是这个函数的编写方式的一个怪癖,你不能依赖它在其他 Python 版本或非标准 Python 实现中以这种方式工作。
Python中的所有数据均通过引用存储。 (C 实现中的 PyObject*
)您发现 .split()
在找不到定界符时只是返回 self
作为优化。找到分隔符后,它必须为每个部分创建单独的字符串对象,因此它们是单独的对象。
(与 Java 不同,"primitives" 和 "reference/class types" 具有截然不同的数据类型,并且与它们的行为也不同)
>>> 'hi'.split()[0] is 'hi'
True
>>> 'hi there'.split()[0] is 'hi'
False
>>> 'hi there again'.split()[0] is 'hi'
False
我的假设:
第一行split只有一个元素,其他两行有多个元素。我相信,虽然像 str
这样的 Python 基元在函数中按值存储在内存中,但函数之间将有单独的分配以简化内存管理。我认为 split()
是其中一个函数,它通常会分配新的字符串。但它也处理不需要任何拆分的输入的边缘情况(例如 'hi'
),其中只返回原始字符串引用。我的解释正确吗?
正如我在评论中所说:
'hi there again'.split()[0] == 'hi'
>>True
实际上你的问题有点一针见血 - 这是一个身份。
I believe that while Python primitives like str are stored in memory by value within a function, there will be separate allocations across functions to simplify memory management.
Python 的对象分配不会那样工作。 "primitives" 没有一个真正的概念,除了字节码编译器为合并常量所做的一些事情之外,两个对象是在同一个函数中创建还是在不同函数中创建并不重要。
没有比指出来源更好的答案了,所以 here it is:
Py_LOCAL_INLINE(PyObject *)
STRINGLIB(split_whitespace)(PyObject* str_obj,
const STRINGLIB_CHAR* str, Py_ssize_t str_len,
Py_ssize_t maxcount)
{
...
#ifndef STRINGLIB_MUTABLE
if (j == 0 && i == str_len && STRINGLIB_CHECK_EXACT(str_obj)) {
/* No whitespace in str_obj, so just use it as list[0] */
Py_INCREF(str_obj);
PyList_SET_ITEM(list, 0, (PyObject *)str_obj);
count++;
break;
}
如果它没有找到任何可拆分的空格,它只会重复使用返回列表中的原始字符串对象。这只是这个函数的编写方式的一个怪癖,你不能依赖它在其他 Python 版本或非标准 Python 实现中以这种方式工作。
Python中的所有数据均通过引用存储。 (C 实现中的 PyObject*
)您发现 .split()
在找不到定界符时只是返回 self
作为优化。找到分隔符后,它必须为每个部分创建单独的字符串对象,因此它们是单独的对象。
(与 Java 不同,"primitives" 和 "reference/class types" 具有截然不同的数据类型,并且与它们的行为也不同)