Jim*_*ard 47 python identity tuples python-3.x python-internals
根据我的意识,使用[], {}或()实例化对象会分别返回一个list, dict或新的实例tuple; 具有新标识的新实例对象.
这对我来说非常清楚,直到我实际测试它并且我注意到() is ()实际返回True而不是预期False:
>>> () is (), [] is [], {} is {}
(True, False, False)
Run Code Online (Sandbox Code Playgroud)
正如所料,与创建对象时,这种行为还表现list(),dict()并tuple()分别为:
>>> tuple() is tuple(), list() is list(), dict() is dict()
(True, False, False)
Run Code Online (Sandbox Code Playgroud)
我可以在状态文档中tuple()找到的唯一相关信息:
[...]例如,
tuple('abc')退货('a', 'b', 'c')和tuple([1, 2, 3])退货(1, 2, 3).如果没有给出参数,构造函数会创建一个新的空元组().
可以说,这还不足以回答我的问题.
那么,为什么空元组具有相同的身份,而其他像列表或词典不具有相同的身份?
Jim*_*ard 53
Python在内部创建了一个C元组对象列表,其第一个元素包含空元组.每次tuple()或()使用,Python会返回包含在上述现有的对象C列表,而不是创建一个新的.
这种机制不存在,dict或者list相反,每次都是从头开始重新创建的对象.
这很可能与以下事实有关:不可变对象(如元组)无法更改,因此保证在执行期间不会更改.在考虑frozenset() is frozenset()回报时,这进一步巩固True; 像()空一样frozenset 被认为是执行中的单例CPython.对于可变对象,这种保证不到位,因此,没有动机缓存它们的零元素实例(即它们的内容可能随着身份保持不变而改变).
请注意: 这不是人们应该依赖的东西,即不应该将空元组视为单身.文档中没有明确提出这样的保证,因此应该假设它是依赖于实现的.
在最常见的情况下,实现CPython是使用两个宏编译PyTuple_MAXFREELIST并PyTuple_MAXSAVESIZE设置为正整数.这些宏的正值导致创建具有大小的tuple对象数组PyTuple_MAXSAVESIZE.
当PyTuple_New被调用的参数,size == 0它会确保一个新的空的元组添加如果它不存在的名单:
if (size == 0) {
free_list[0] = op;
++numfree[0];
Py_INCREF(op); /* extra INCREF so that this is never freed */
}
Run Code Online (Sandbox Code Playgroud)
然后,如果请求新的空元组,则将返回位于此列表的第一个位置的那个,而不是新实例:
if (size == 0 && free_list[0]) {
op = free_list[0];
Py_INCREF(op);
/* rest snipped for brevity.. */
Run Code Online (Sandbox Code Playgroud)
引发激励的另一个原因是函数调用构造一个元组来保存将要使用的位置参数.这可以在以下load_args函数中看到ceval.c:
static PyObject *
load_args(PyObject ***pp_stack, int na)
{
PyObject *args = PyTuple_New(na);
/* rest snipped for brevity.. */
Run Code Online (Sandbox Code Playgroud)
do_call在同一个文件中调用via .如果参数的数量na为零,则将返回空元组.
从本质上讲,这可能是一个经常执行的操作,因此每次都不重建一个空元组是有意义的.
更多的答案揭示CPython了不可变的缓存行为:
| 归档时间: |
|
| 查看次数: |
3853 次 |
| 最近记录: |