四时宝库

程序员的知识宝库

CPython源码阅读13-bytes对象合并底层原理

当我们在键盘上敲下如下代码时,它的底层是如何实现的。第一行对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;
}

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接