当我们在键盘上敲下如下代码时,它的底层是如何实现的。第一行对bytes1这个bytes对象赋值,第二行对bytes2这个bytes对象赋值,第三行两个bytes对象相加。从结果来看,把两个bytes对象合并在一起了,使用这个“+”符号,通过多态实现了bytes对象合并(concat)这一功能。
通过这个图示,理解一下源码
//cpython-master\Objects\bytesobject.c
static PyObject *
bytes_concat(PyObject *a, PyObject *b)
{
Py_buffer va, vb; //两个表示缓冲区的局部变量
PyObject *result = NULL;//用于保存结果
va.len = -1;
vb.len = -1;//初始值为-1,表示此时缓冲区为空
//将a、b中的ob_sval拷贝到缓冲区中,返回非0,则拷贝成功
if (PyObject_GetBuffer(a, &va, PyBUF_SIMPLE) != 0 ||
PyObject_GetBuffer(b, &vb, PyBUF_SIMPLE) != 0) {
//用于检查两个合并的对象是否都为bytes对象
PyErr_Format(PyExc_TypeError, "can't concat %.100s to %.100s",
Py_TYPE(b)->tp_name, Py_TYPE(a)->tp_name);
goto done;//释放缓冲区,防止内存泄露
}
//a与b中是否有一个长度为0,如果是,直接将其中一个赋值给result
if (va.len == 0 && PyBytes_CheckExact(b)) {
result = b;
Py_INCREF(result);//增加result的引用计数
goto done;//释放缓冲区,防止内存泄露
}
if (vb.len == 0 && PyBytes_CheckExact(a)) {
result = a;
Py_INCREF(result);
goto done;
}
//判断两个字节序列合并之后,是否超过最大限制
if (va.len > PY_SSIZE_T_MAX - vb.len) {
PyErr_NoMemory();
goto done;
}
//为result分配内存,大小为 va.len + vb.len
result = PyBytes_FromStringAndSize(NULL, va.len + vb.len);
if (result != NULL) {
//将va缓冲区中的buf内容拷贝到result的ob_sval中。拷贝长度为 va.len
memcpy(PyBytes_AS_STRING(result), va.buf, va.len);
//将vb缓冲区中的buf内容拷贝到result的ob_sval中。拷贝长度为 vb.len。从 va.len的位置开始拷贝
memcpy(PyBytes_AS_STRING(result) + va.len, vb.buf, vb.len);
}
done:
if (va.len != -1)
PyBuffer_Release(&va);
if (vb.len != -1)
PyBuffer_Release(&vb);
return result;
}