2011年3月27日星期日

python源码解析读书笔记(一)——内置对象

1.类型的类型
    obj int(10).ob_type -> PyInt_Type
    PyInt_Type.ob_type -> PyType_Type
    PyInt_Type.tp_base -> PyBaseObject_Type
    PyBaseObject_Type.ob_type -> PyType_Type
    PyType_Type.ob_type -> PyType_Type
更精确的参考源码解析262页图。

2.小整数对象
    if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) {
        v = small_ints[ival + NSMALLNEGINTS];
        Py_INCREF(v);
    }

3.大整数对象,空对象池,对象缓存
>>> a = 1000000
>>> b = 2000000
>>> id(a) == id(1000000)
False
>>> id(100000) == id(100000)
True
最后一个是因为python解析器在解析对象的时候,对前后生成的对象进行了缓存。经过测试,对文件也有效。

4.字符串对象复用和缓存
>>> c = 'qazwsxedcrfvt'
>>> c += 'gbyhnujmikolp'
>>> a = 'qazwsxedcrfvtgbyhnujmikolp'
>>> id(a) == id(c)
False
>>> a = 'abc'
>>> b = 'def'
>>> c = 'abc'
>>> id(a) == id(c)
True
>>> b = 'abcde'
>>> id(b[1]) == id(c[1])
True
缓存原理同上,对于长度为0, 1的小字符串,永久缓存。

5.free_list对象缓存的机制
每个类别有自己的free_list对象,用于缓存已经被销毁的对象。目前尚不清楚GC是否会定时释放这部分内存,但是python在对象引用到0时是不释放对象的,而且多数情况下表现为内存泄漏。而且多种对象的free_list不能互相通用,继承子类也不适用。

6.list对象的行为
list对象用一种vector等同的方法处理对象池。因此随机插入(尤其是头部插入)一个对象超长队列会引发大量的内存复制行为。

7.dict对象的索引方案
dict对象的索引方案使用的是哈希表,而且是开放地址法的哈希表。当装载率达到一定规模后,会新申请一块内存,将有效数据复制过去。最小的表空间为8个对象,当装载率超过2/3时,会扩大规模到当前active的4倍(超过50000个对象为2倍)。目前为止,在对象被删除后,其表空间并不释放。因此曾经增长的非常大的dict对象,可以定期复制以回收空间。

8.dict的用法注释
从序列中移除重复对象
    dict.fromkeys(seqn).keys()
计算序列中元素出现次数
    for e in seqn: d[e] = d.get(e,0) + 1
词典中移除大量元素
    d = dict([(k, v) for k, v in d.items() if k != xxx])
词典中访问可能不存在的元素(当不存在的风险高于5%时)
    o = d.get(k, default)
词典中访问可能不存在的元素(当不存在的风险低于5%时)
    try: o = d[k]
    except KeyError: o = default

没有评论: