Python源码学习笔记(1 基本数据类型)

来源:互联网 发布:flv视频合并软件 编辑:程序博客网 时间:2024/05/10 16:25

分类: python 编程 C++
 155人阅读 评论(0) 收藏 举报
pythonlistimmutable语言string算法
   Python源码剖析 这本书相当好。
    我用Python也有几个月时间了,这时候读Python源码,会对提高C语言水平、Python水平、算法基础都有相当的帮助。
    我目前只看了最前面的数据类型基础,也就是网上可以下载到的:
        Python源码剖析.chm
    这个文件。学习心得嘛,就是多看多想,有问题的时候再调试Python源码验证想法。
    欢迎留言交流。

衷心的感谢《Python源码剖析》作者
Robert Chen(search.pythoner@gmail.com)



Chapter 1. PyObject


对象大小一旦创建就不变了

PyObject    {
    Py_ssize_t ob_refcnt;
    struct _typeobject *ob_type;
}

PyVarObject    {
    Py_ssize_t ob_refcnt;
    struct _typeobject *ob_type;
    Py_ssize_t ob_size;        //元素个数
}

★ 内存空间大小一定和对象类型有关


typedef struct _typeobject {
    PyObject_VAR_HEAD
    const char *tp_name;
    Py_ssize_t tp_basicsize, tp_itemsize;
   
    struct PyMethodDef *tp_methods;
    struct PyMemberDef *tp_members;
    struct PyGetSetDef *tp_getset;
    struct _typeobject *tp_base;
    PyObject *tp_dict;
}

PyTypeObject的类型是用自身定义的?
PyTypeObject PyType_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
}

★ C语言实现多态只需要多加一个结构体ob_type,把ob_type*组合进去即可?
指向类型对象的指针不会增加类型对象的引用计数。

此设计方法在C语言中用处颇大,参考云风相关博文《我所偏爱的 C 语言面向对象编程范式》
http://blog.codingnow.com/2010/03/object_oriented_programming_in_c.html
但是云风的文章写的不明不白,互相印证一下就ok了。


    Chapter 2. PyIntObj
最有特色的地方有两处:
1、小整数特殊处理,永远只存在一份
2、用多个链表管理所有整数,可以看作特制的内存分配器。最神奇的是删除某个整数对象时的行为。

此章有意思的地方是链表使用时的灵活技巧,很有意思。


    Chapter 3. PyStringObj
PyStringObj是一种immutable对象,内容不可变。这和能做Key有关系吗?
Intern机制
void PyString_InternInPlace(PyObject **p)
{
    register PyStringObject *s = (PyStringObject *)(*p);
    PyObject *t;
    if (s == NULL || !PyString_Check(s))
        Py_FatalError("PyString_InternInPlace: strings only please!");
   
    if (!PyString_CheckExact(s))
        return;
    if (PyString_CHECK_INTERNED(s))
        return;

1、Intern的字符串必须是基本的PyString类型,派生类无此功能
2、Intern表是一个PyDict,所以要先把原始字符串变成PyString,之后才能插入Intern表。
3、PyString自身在Intern表里有引用,不合理。所以这个地方有trick,强行修改引用计数。
4、根据多次调试,Python内部使用以下接口创建字符串,以保证字符串尽可能的Intern
PyObject * PyString_InternFromString(const char *cp)

按某优化高手的说法,String用引用计数统一管理是目前来看必不可少的优化方法,无论任何领域。Python的这部分实现很简洁


    Chapter 4. PyListObject
和string不同,list是可变对象

list的实现比较容易理解,是一个保存PyObject*的数组

list的resize算法
static int list_resize(PyListObject *self, int newsize)
1.newsize > ob_size && newsize < allocated :简单调整ob_size值。
2.newsize < ob_size && newsize > allocated/2 :简单调整ob_size值。
3.newsize < ob_size && newsize < allocated/2 :调用realloc,重新分配空间。
4.newsize > ob_size && newsize > allocated :调用realloc,重新分配空间。

static int list_ass_slice(PyListObject*, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject* v)
这个函数可以做切片删除、切片赋值替换、切片赋值插入等等。我还没用过list的这个功能

list在销毁时进入free_list表,下次创建新的list时可以复活老list。但是销毁list的时候必须把内容全销毁,所以并非省了很多事。

C语言技巧:do {} while(0)

    Chapter 5. PyDictObject
一、基础
PyDictObject实际上维护了一堆entry
Python Dict容器的最大特点是用多次探测的方法处理hash collision,与常见算法差异较大。相应的就引入了active, dummy, unused三种entry状态。

二、搜索策略
key为PyString时的搜索策略:
static dictentry* lookdict_string(dictobject *mp, PyObject *key, register long hash)
通用搜索策略:
static dictentry* lookdict(dictobject *mp, PyObject *key, register long hash)
由于Python内部底层大量使用PyString,而且PyString极为常见,所以将其特化达到优化的目的。

根据Python Dict的特点,搜索策略的核心就是——
1、找到匹配的Key则返回相应entry
2、找到dummy时继续查找,把此dummy缓存一下。
3、找到Unused entry时,搜索必然会停止,返回上一个dummy或者是这个unused entry。

三、插入和调整
ma_fill 指的是dummy数量+active数量
ma_used 指的是active数量
PyDict_SetItem这个函数里,会把fill、used大小与table大小相比较,重新resize Dict
dictresize这个函数里,必要时会重新申请一个table,将元素重新插入一次,这时顺便去掉所有dummy节点。
0 0
原创粉丝点击