CPython3 中 str 类和 bytes 类的一些实现细节

CPython在github上的官方 repo: https://github.com/python/cpython
下面的总结都是给予我当前时间点(2019-05)看到的最新版本,3.8.0 alpha 4

首先在 python2 中,str类对应的 C struct 是 PyStringObject,但是在 python3 中该 strcut 改成了 PyBytesObject,但是 python3 中不再使用 PyBytesObject 作为 str 类的底层实现,这是因为 python2 中 str 默认是 bytes,转成 unicode 需要加 ‘u’ 前缀;而 python3 中默认是 unicode,转成 bytes 需要加 b 前缀。

#python2
s = "abc" # bytes
s = u"abc" # unicode

#python3
s = "abc" # unicode
s = b"abc" # bytes

PyBytesObject

PyBytesObject 定义在 include/bytesobject.h 文件:

#ifndef Py_LIMITED_API
typedef struct {
    PyObject_VAR_HEAD
    Py_hash_t ob_shash;
    char ob_sval[1];

    /* Invariants:
     *     ob_sval contains space for 'ob_size+1' elements.
     *     ob_sval[ob_size] == 0.
     *     ob_shash is the hash of the string or -1 if not computed yet.
     */
} PyBytesObject;
#endif

ob_shash 是 hash 值,可以计算一次后缓存起来,ob_sval 就是指向具体内存的指针。
PyObject_VAR_HEAD 定义在 Include/object.h 的一个 macro(宏),这个 macro 是用于标记大多数可变长对象的。(注意不是可变对象

#define PyObject_VAR_HEAD      PyVarObject ob_base;

typedef struct {
    PyObject ob_base;
    Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;

其中 ob_size 是元素个数,而 ob_base 是一个所有 python 对象的抽象 struct,定义如下:

typedef struct _object {
    _PyObject_HEAD_EXTRA
    Py_ssize_t ob_refcnt;
    struct _typeobject *ob_type;
} PyObject;

ob_refcnt 是引用计数,ob_type 就是实际指向对象的指针。

至此整个结构体的脉络比较清晰,还是比较容易看懂的

具体的一些对 PyBytesObject 操作的函数是定义在 Objects/bytesobject.c 文件里的,这里抽取几个进行分析。

第一个是 PyBytes_FromString 函数,它是从一个 char* 中创建一个 PyBytesObject 对象

PyObject *
PyBytes_FromString(const char *str)
{
    size_t size;
    PyBytesObject *op;

    assert(str != NULL);
    size = strlen(str);
    //检查传入的字符串长度是否过长
    if (size > PY_SSIZE_T_MAX - PyBytesObject_SIZE) {
        PyErr_SetString(PyExc_OverflowError,
            "byte string is too long");
        return NULL;
    }

    //如果长度为0, 则返回 nullstring
    if (size == 0 && (op = nullstring) != NULL) {
#ifdef COUNT_ALLOCS
        _Py_null_strings++;
#endif
        Py_INCREF(op);
        return (PyObject *)op;
    }

    //characters 是一个 单字符str缓冲池, 如果长度为1,就返回缓冲池地址
    if (size == 1 && (op = characters[*str & UCHAR_MAX]) != NULL) {
#ifdef COUNT_ALLOCS
        _Py_one_strings++;
#endif
        Py_INCREF(op);
        return (PyObject *)op;
    }

    /* Inline PyObject_NewVar */
    // 分配长度为 PyBytesObject_SIZE+size 的内存空间, 注意此时 op.ob_sval 指向的是一个长度为 size+1 的内存空间
    op = (PyBytesObject *)PyObject_MALLOC(PyBytesObject_SIZE + size);
    if (op == NULL)
        return PyErr_NoMemory();
    (void)PyObject_INIT_VAR(op, &PyBytes_Type, size);
    op->ob_shash = -1;
    // 将传入的 str 值拷贝到 op 结构体中
    memcpy(op->ob_sval, str, size+1);
    /* share short strings */
    if (size == 0) {
        nullstring = op;
        Py_INCREF(op);
    } else if (size == 1) {
        characters[*str & UCHAR_MAX] = op;
        Py_INCREF(op);
    }
    return (PyObject *) op;
}

猜你喜欢

转载自www.cnblogs.com/daghlny/p/10916755.html
今日推荐