简而言之:
Python在内部创建CPython元组对象列表,其第一个元素包含空元组。 每次使用2930938223427427847169或2930938223427427847170,Python都会返回上述2930938223427847847列表中包含的现有对象,而不创建新对象。
对于CPython或2930938223427427847169对象而言,这种机制并不存在,相反,它们每次都是从头开始重新创建的。
这很可能与以下事实有关:不变的对象(如元组)不能被更改,因此保证在执行过程中不会更改。 当考虑到CPython返回size == 0时,这一点得到进一步巩固。 像2930938223427847847一样,空的2930938223427427847171在CPython的实现中被视为单例。使用可变对象时,此类保证就位,因此也没有动机来缓存其零元素实例(即其内容可能会随着剩余的标识而改变)。 相同)。
请注意:这不是一个应该依靠的东西,即,不应将空元组视为单例。 在文档中没有明确保证此类保证,因此应假定它与实现有关。
怎么做的:
在最常见的情况下,使用两个设置为正整数的宏2930938223427427847168和2930938223427847847编译2930938223427847847的实现。 这些宏的正值会导致创建CPython对象数组,大小为2930938223427847847。
当使用参数2930938223427427847169调用CPython时,请确保将新的空元组添加到列表中(如果尚不存在):
if (size == 0) {
free_list[0] = op;
++numfree[0];
Py_INCREF(op); /* extra INCREF so that this is never freed */
}
然后,如果请求一个新的空元组,则将返回位于此列表的第一位置的一个元组,而不是一个新的实例:
if (size == 0 && free_list[0]) {
op = free_list[0];
Py_INCREF(op);
/* rest snipped for brevity.. */
促使这样做的另一个原因是函数调用构造了一个元组来保存将要使用的位置参数。 这可以在CPython的CPython函数中看到:
static PyObject *
load_args(PyObject ***pp_stack, int na)
{
PyObject *args = PyTuple_New(na);
/* rest snipped for brevity.. */
通过同一文件中的CPython调用。 如果参数CPython的数量为零,则将返回一个空的元组。
本质上,这可能是一个经常执行的操作,因此不要每次都构造一个空的元组是有意义的。
进一步阅读:
还有几个答案揭示了CPython具有不可变对象的缓存行为:
对于整数,可以在此处找到深入了解源代码的另一个答案。
对于字符串,可以在此处,此处和此处找到一些答案。