python数组切片赋值_列表切片赋值给另一个变量,浅拷贝原理解析

把一个列表的切片赋值给另一个变量,Python内部发生了什么?

如下所示,创建列表a,然后把它的一段切片赋值给b:

>>>

>>> a = [2, "Hello", 5, [3,4,7],{1:2}] # 创建列表a

>>>

>>> a

[2, 'Hello', 5, [3, 4, 7], {1: 2}]

>>>

>>>

>>> a[2:5] # 访问a的切片

[5, [3, 4, 7], {1: 2}]

>>>

>>>

>>> b = a[2:5] # 把a切片赋值给b

>>>

>>> b

[5, [3, 4, 7], {1: 2}]

>>>

列表在C语言当中是一个PyListObject结构体,这个结构体当中有一个成员ob_item,它是一个指针,指向一块内存,而这块内存存储了一系列指针,每一个指针分别指向列表的每一个成员。如下图所示:

在访问a的切片时,会新创建一个列表对象,也就是PyListObject结构体,并为它的ob_item指针分配一块内存,然后把a中的ob_item所指向的,切片所需的内容拷贝过去。

把切片赋值给b,实际上就是让b指向了这一个新创建的列表对象。

由于ob_item所指向的内存所存储的是一系列指针,拷贝时仅拷贝了这些指针,所以b和部分a成员实际上指向相同的对象,这些对象并没有重新创建一份,这也就是所谓的浅拷贝。下图所示红色部分就是拷贝的内容。

C代码:

把切片赋值给b时,调用了如下所示函数创建新列表,并根据传入的参数把对应的切片内容拷贝到新列表当中。

static PyObject *

list_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh)

{

PyListObject *np;

PyObject **src, **dest;

Py_ssize_t i, len;

len = ihigh - ilow;

np = (PyListObject *) list_new_prealloc(len); // 申请了一块内存用来存储新列表

if (np == NULL)

return NULL;

src = a->ob_item + ilow;

dest = np->ob_item;

for (i = 0; i < len; i++) { // 将列表a的ob_item中对应的值复制到新列表中

PyObject *v = src[i];

Py_INCREF(v);

dest[i] = v;

}

Py_SIZE(np) = len;

return (PyObject *)np;

}

上面代码中的申请内存的函数如下所示:

static PyObject *

list_new_prealloc(Py_ssize_t size)

{

PyListObject *op = (PyListObject *) PyList_New(0); // 参数0是指PyListObject中的ob_item成员不申请内存

if (size == 0 || op == NULL) { // 它在下面代码中单独申请

return (PyObject *) op;

}

assert(op->ob_item == NULL);

op->ob_item = PyMem_New(PyObject *, size); // 为ob_item申请内存

if (op->ob_item == NULL) {

Py_DECREF(op);

return PyErr_NoMemory();

}

op->allocated = size;

return (PyObject *) op;

}

本作品采用《CC 协议》,转载必须注明作者和本文链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值