我在python中尝试了这些,并得到了相当混乱的结果。
>>> p = [1, 2, 3, 4, 5, 6, 7, 8]
>>> p
[1, 2, 3, 4, 5, 6, 7, 8]
>>> p[2:8:2]
[3, 5, 7]
>>> id(p[2:8:2])
37798416
>>> id(p[2:8:2])
37798416
>>> id(p[2:8:2])
50868392注意第三次更改id的方式!
>>> id(p[2:8:2])
37798336又变了!Question#1:这是怎么发生的,为什么会发生?
Question#2:
>>> p[2:8:2] = [33,55,77]
>>> p
[1, 2, 33, 4, 55, 6, 77, 8]python到底是如何“存储”p2:8:2的?(也许“商店”不是正确的词,但我希望你能理解)。它看起来不像是一个与原始列表不同的列表(尽管它是由原始列表中不连续的不可变项组成的),因为对这个列表的更改反映在原始列表中!
发布于 2019-06-27 01:04:50
切片,除了罕见的例外,制造全新的副本,无论你正在切片。因此,所有id检查都告诉您,有时新的list重用上次的内存,有时使用不同的内存。确切的行为是纯粹的实现细节。在CPython (参考解释器)中,id恰好对应于内存地址,所以您所看到的只是分配程序的行为工件,而不是切片的深层意义。
关于问题2:当在赋值上下文中使用切片修改原始序列时,它根本不会创建新的list。不要试图在切片(面向读,生成新序列)和片分配(面向写,修改现有序列)之间划出有意义的相似之处;遮罩下的行为几乎在各个方面都不同。
发布于 2019-06-27 01:04:33
问题1的:
保证对象的id在该对象的生存期内是唯一的,并且保持不变。请参阅在Python库文档中
id(object)-返回对象的标识。这是一个整数,它保证该对象在其生存期内是唯一的和常量的。两个寿命不重叠的对象可能具有相同的id()值。
由于您正在使用切片创建和销毁对象,因此id实际上是遵循规则的。
如果您使用的是引用(我怀疑是最常见的)实现CPython,那么它只会给出对象的内存地址。源代码可以在Python/bltinmodule.c中找到,下面对其进行了简化和注释:
static PyObject *builtin_id(PyModuleDef *self, PyObject *v) {
PyObject *id = PyLong_FromVoidPtr(v); // Turn object address into
return id; // long and return it.
}这确保了它是唯一的,并且内存分配调用的变幻莫测和顺序也解释了为什么它可以重复和/或不同。
问题2的:
分配给“片”实际上并不涉及创建切片对象并将其赋值。它只是将已经存在的对象中由片表示法指定的某些值设置为赋值的右侧给定的值。
更多细节可以在sliceobject源代码中的CPython文件中找到,特别是对象/切片对象。c和包括/切片对象。。这涉及到创建一个PySliceObject,它由一个{start, stop, step}元组组成。
当您将此元组应用于赋值右侧(如x = y[2:8:2] )的对象时,它将使用PySliceObject创建基于y的新列表x,只获取相关元素。
在左手边使用时,例如x[2:8:2] = [33,55,77],它使用PySliceObject来决定将x的哪些元素设置为右侧的值。
https://stackoverflow.com/questions/56782639
复制相似问题