python - 为什么 '() is ()'和 '[] is []'返回False时 '{} is {}'返回True?

标签 python python-3.x tuples identity python-internals

据我所知,使用 []、{}() 实例化对象会返回 list、dict< 的新实例tuple 分别;具有新身份的新实例对象。

这对我来说很清楚,直到我实际测试它,我注意到 () is () 实际上返回 True 而不是预期的 False:

>>> () is (), [] is [], {} is {}
(True, False, False)

正如预期的那样,在使用 list() 创建对象时也会出现这种行为。 , dict()tuple()分别:

>>> tuple() is tuple(), list() is list(), dict() is dict()
(True, False, False)

我可以在 the docs for tuple() 中找到的唯一相关信息状态:

[...] For example, tuple('abc') returns ('a', 'b', 'c') and tuple([1, 2, 3]) returns (1, 2, 3). If no argument is given, the constructor creates a new empty tuple, ().

可以说,这不足以回答我的问题。

那么,为什么空元组具有相同的身份,而列表或字典等其他人则没有?

最佳答案

简而言之:

Python 在内部创建一个 C 元组对象列表,其第一个元素包含空元组。每次使用 tuple()() 时,Python 都会返回上述 C 列表中包含的现有对象,而不是创建新对象.

对于 dictlist 对象不存在这种机制,相反,每次都从头开始重新创建

这很可能与不可变对象(immutable对象)(如元组)无法更改,因此保证在执行期间不会更改的事实有关。当考虑到 frozenset() is frozenset() 返回 True; 时,这一点进一步巩固。比如 () 一个空的 frozenset is considered an singleton in the implementation of CPython .对于可变对象,没有这样的保证,因此,没有动机缓存它们的零元素实例(即它们的内容可能会随着身份保持不变而改变)。

注意: 这不是人们应该依赖的东西,即不应将空元组视为单例。文档中没有明确做出这样的保证,所以应该假设它是依赖于实现的。


它是怎么做的:

在最常见的情况下,CPython 的实现是用两个宏编译的 PyTuple_MAXFREELISTPyTuple_MAXSAVESIZE设置为正整数。这些宏的正值导致创建 array of tuple objects大小为 PyTuple_MAXSAVESIZE.

当使用参数 size == 0 调用 PyTuple_New 时,它确保 add a new empty tuple如果列表尚不存在,则添加到列表中:

if (size == 0) {
    free_list[0] = op;
    ++numfree[0];
    Py_INCREF(op);          /* extra INCREF so that this is never freed */
}

然后,如果请求一个新的空元组,则位于 first position of this list 中的空元组将返回而不是新实例:

if (size == 0 && free_list[0]) {
    op = free_list[0];
    Py_INCREF(op);
    /* rest snipped for brevity.. */

导致这样做的另一个原因是函数调用构造一个元组来保存将要使用的位置参数。这可以在 load_args 中看到ceval.c 中的函数:

static PyObject *
load_args(PyObject ***pp_stack, int na)
{
    PyObject *args = PyTuple_New(na);
    /* rest snipped for brevity.. */

通过 do_call 调用在同一个文件中。如果参数 na 的数量为零,则将返回一个空元组。

本质上,这可能是一个频繁执行的操作,因此不要每次都重建一个空元组是有意义的。


延伸阅读:

更多答案阐明了 CPython 的不可变缓存行为:

  • 对于整数,可以找到另一个在源代码中挖掘的答案 here .
  • 对于字符串,可以找到一些答案 here , herehere .

关于python - 为什么 '() is ()'和 '[] is []'返回False时 '{} is {}'返回True?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38328857/

相关文章:

python - 如何从 model.predict() 结果中获取单个值

python - 使用python循环在jira中创建票据

java - 如何终止java套接字发送到python的数据?

java - Java 中的 C++ Pair<L,R> 等价物是什么?

解析元组的 Pythonic 方式

python - 适当的 DataFrame 切片修改

python - 有没有一种简单的方法可以通过 sympy 获取某个域中函数的所有不连续性?

python-3.x - 如何在python3中导入cv2?

python - 如何修复 django-mptt 中没有 child 到 parent 的问题?

python - 根据列表中每个元组的长度克隆列表中的元组