最近在看 《 Python 源码剖析》
类似 [obj] * count 的表达式,编译成字节码之后为
```
# 构建 [obj]
0 LOAD_GLOBAL 0 (obj)
2 BUILD_LIST 1
# 读取 count
4 LOAD_GLOBAL 1 (count)
# 实现 [obj] * count
6 BINARY_MULTIPLY
```
而 BINARY_MULTIPLY 指令在源码中的实现为
```
TARGET(BINARY_MULTIPLY) {
PyObject *right = POP(); # 获取 count
PyObject *left = TOP(); # 获取 [obj]
# 获取相乘的结果
PyObject *res = PyNumber_Multiply(left, right);
Py_DECREF(left);
Py_DECREF(right);
SET_TOP(res);
if (res == NULL)
goto error;
DISPATCH();
}
```
而 PyNumber_Multiply 最后调用的是 ->ob_type->tp_as_sequence->sq_repeat 函数,
```
# repeatfunc = sq_repeat
# seq = [obj]
# count = count
return (*repeatfunc)(seq, count);
```
该函数在 list 类型的实现为
```
static PySequenceMethods list_as_sequence = {
...
(ssizeargfunc)list_repeat, /* sq_repeat */
...
};
```
下面是 list_repeat 简化后的代码
```c
static PyObject *
list_repeat(PyListObject *a, Py_ssize_t n)
{
...
PyObject *elem;
# np 指向新分配的 count 大小的 list 对象
np = (PyListObject *) PyList_New(size);
items = np->ob_item;
# 如果 [obj] 的对象大小为 1 的话,我们这里就是如此
if (Py_SIZE(a) == 1) {
# 获取 obj,即这里的 elem
elem = a->ob_item[0];
for (i = 0; i < n; i++) {
# 因为 elem 是指针,所以这里新的 list 的 items 里面包含的是原有的 obj 的引用,而不是复制
items[i] = elem;
Py_INCREF(elem);
}
return (PyObject *) np;
}
...
}
```
所以 [obj] * count 最后获得是包含 count 个 obj 引用的新 list
在 github 上写了一篇 blog,更加详细的论述了这个问题,有兴趣的可以点击观看
https://github.com/shidenggui/blog/issues/16