閱讀567 返回首頁    go 京東網上商城


[筆記]Python的字符串對象

PyStringObject定義在stringobject.h中,附有不少注釋說明。
1. PyStringObject實際上是一組字符,以'\0'結尾,且因為有隻是長度的變量,所以也可以包含'\0'作為內容。
2. PyStringObject是不可變對象,所以a = "hello"和a = "world"先後執行後,a指向的是不同的對象了。
3. PyStringObject保存了hash值避免重複計算。
4. 采用intern機製來處理相同的字符串對象。

結構體定義如下:
typedef struct {
    PyObject_VAR_HEAD          //不定長對象
    long ob_shash;             //如果還沒計算,為-1
    int ob_sstate;             //如果該字符串在interned字典中,則該標誌不為0。而且在這種情況下,兩個來自interned字典的引用不算進ob_refcnt
    char ob_sval[1];           //用來作為指針指向保存字符串的內存區域,包含ob_size+1個元素
} PyStringObject;


計算哈希值的算法有必要MARK下,以後可以參考使用。
static long
string_hash(PyStringObject *a)
{
    register Py_ssize_t len;
    register unsigned char *p;
    register long x;

    if (a->ob_shash != -1)
        return a->ob_shash;
    len = Py_SIZE(a);
    p = (unsigned char *) a->ob_sval;
    x = *p << 7;
    while (--len >= 0)
        x = (1000003*x) ^ *p++;
    x ^= Py_SIZE(a);
    if (x == -1)
        x = -2;
    a->ob_shash = x;
    return x;
}



intern機製是用來確保相同的值的字符串對象隻有一個存在,並且使得比較操作可以僅僅通過指針比較來完成。
它實際上是維護了一個字典(dict/map)interned,當字符串被interned時,會查找字典中鍵的存在,如果沒有則放入。
這種方法可以在空間上節省,並不能節省時間,因為要判斷是否存在於interned字典中,需要先創建字符串對象,才能去表中查找。
此外,這種方法默認針對Python的關鍵字、單字符、空串等。
當然,Python也提供了intern()內置函數來緩存用戶想要的字符串對象。
緩存hash值以及intern機製為解釋器加速了20%。

最後,是關於字符串的連接。
比如:str = str1 + str2 + str3 + str4,由於PyStringObject is immutable,所以會為3個+號執行3次內存的分配和複製
而如果將待連接的字符串放入可迭代對象中,使用string_join(PyStringObject的join操作),就會一次計算所需的總共內存大小,一次分配,然後再全部複製過去。


JasonLee     2011.08.08     0:33

最後更新:2017-04-02 22:16:35

  上一篇:go jQuery提交多個表單
  下一篇:go Oracle Job 知識