Python源码剖析笔记1——Python对象初见

工作整两年了,用python最多,然而对于python内部机制不一定都清楚,每天沉醉于增删改查的简单逻辑编写,实在耗神。很多东西不用就忘记了,比如C语言,正好,python源码用C写的,分析python源码的同时又能温故C语言基础,实在是件很好的事情。另外,还有陈儒大神的《python源码剖析》做指引,分析也不至于没头没脑。期望在一个月的业余时间,能有所小成,以此为记。

1 python中的对象

python中,一切东西都是对象,在c语言实现中对应着结构体。首先当然还是从python内建对象开始看起,最基本的是PyIntObject, PyStringObject, PyListObject, PyDictObject这几个,他们分别属于int,string, list, dict类型。从python2.2之后有了new style class之后,这些内置对象都是继承自object类型,object在代码中对应PyBaseObject_Type。比如我们赋值语句a=3,那么a就是一个PyIntObject对象,它的类型是int,在代码中对应PyInt_Type,PyInt_Type也是一种对象,我们称之为类型对象。那么PyInt_Type它的类型是什么呢,答案是type, 对应到代码中就是PyType_Type。当然object也是一个类型对象,它的类型也是PyType_Type。这么一层层下去,PyType_Type也是个对象,那它的类型又是什么呢,没错,答案就是它的类型就是它自己,。看下面的验证代码:

##内建对象测试
In [1]: a = 3

In [2]: type(a)
Out[2]: int

In [3]: type(int)
Out[3]: type

In [4]: type(type)
Out[4]: type

In [5]: int.__base__
Out[5]: object

In [6]: type(object)
Out[6]: type

先分析下几个基础内建对象在C语言中的结构体以及常用的几个宏,为了方便,我用的也是陈儒大神分析的那个版本一致,版本是2.5.6.源码官网有下载。

// 内建对象基础
#define PyObject_HEAD                   \
        Py_ssize_t ob_refcnt;           \
        struct _typeobject *ob_type;

#define PyObject_HEAD_INIT(type)        \
        1, type,

#define PyObject_VAR_HEAD               \
        PyObject_HEAD                   \
        Py_ssize_t ob_size; /* Number of items in variable part */
#define Py_INVALID_SIZE (Py_ssize_t)-1

typedef struct _object {
        PyObject_HEAD
} PyObject;

typedef struct {
        PyObject_VAR_HEAD
} PyVarObject;

typedef struct _typeobject {
        PyObject_VAR_HEAD
        const char *tp_name; /* For printing, in format "<module>.<name>" */
        Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */
        destructor tp_dealloc;
        printfunc tp_print;
        getattrfunc tp_getattr;
        setattrfunc tp_setattr;
        cmpfunc tp_compare;
        reprfunc tp_repr;
        ...
} PyTypeObject;

typedef struct {
    PyObject_HEAD
    long ob_ival;
} PyIntObject;

typedef struct {
    PyObject_VAR_HEAD
    long ob_shash;
    int ob_sstate;
    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.
     *     ob_sstate != 0 iff the string object is in stringobject.c's
     *       'interned' dictionary; in this case the two references
     *       from 'interned' to this object are *not counted* in ob_refcnt.
     */
} PyStringObject;

如代码中所示,PyObject是所有Python对象的基石,所有后续看到的对象都有一个相同的PyObject头部,从而我们可以在源码中看到所有的对象都可以用PyObject指针指向,这就是面向对象中经常用到的多态的技巧了。Python内部各个函数对象间也是通过PyObject传递,即便本身这是一个PyIntObject类型的对象,代码中并不会用PyIntObject*指针进行传递,这也是为了实现多态。比如下面的函数:

void Print(PyObject* object) {
    object->ob_type->tp_print(object);
}

另外如代码中注释所说的,变长对象的ob_size指的是元素个数,不是字节数目。

2 python对象引用计数

下面是几个常用的操作对象引用计数的宏定义(object.h),一并列出,这里去除了一些调试时用的代码,更容易看明白代码含义。Py_NewReference是初始化时对象时设置引用计数, Py_INCREF和Py_DECREF分别用来增加引用技术和减少引用计数。从代码中可以看到,python增加引用和减少引用都是通过这些宏操作的,**有一点需要注意的是,当对象引用ob_refcnt减小到0时,会调用对象的析构函数,析构函数并不一定会调用free释放内存空间,因为频繁申请和释放内存严重影响性能,所以在后面看到python有大量用到内存池技术,对提升性能有很大效果。

需要说明的是,类型对象是不在引用计数规则之中的,每个对象指向类型对象的指针并不视为类型对象的引用,也就是说不会影响类型对象的引用计数,类型对象永远不会被析构。

#define _Py_NewReference(op) ((op)->ob_refcnt = 1)


#define _Py_Dealloc(op) (*(op)->ob_type->tp_dealloc)((PyObject *)(op)))

#define Py_INCREF(op) ((op)->ob_refcnt++)

#define Py_DECREF(op)                                   \
        if (--(op)->ob_refcnt != 0)                     \
            ;
        else                                            \
            _Py_Dealloc((PyObject *)(op))
            
#define Py_CLEAR(op)                            \
        do {                                    \
                if (op) {                       \
                        PyObject *tmp = (PyObject *)(op);       \
                        (op) = NULL;            \
                        Py_DECREF(tmp);         \
                }                               \
        } while (0)

/* Macros to use in case the object pointer may be NULL: */
#define Py_XINCREF(op) if ((op) == NULL) ; else Py_INCREF(op)
#define Py_XDECREF(op) if ((op) == NULL) ; else Py_DECREF(op)

3 Python对象分类

python中的对象大致可以分为下面几类:

  • 数值对象:如integer,float,boolean
  • 序列集合对象:如string,list,tuple
  • 字典对象:如dict
  • 类型对象:如type
  • 内部对象:如后面会看到的code,function,frame,module以及method对象等。

4 参考资料

  • 《python源码剖析》
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,265评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,274评论 1 288
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,087评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,479评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,782评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,218评论 1 207
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,594评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,316评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,955评论 1 237
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,274评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,803评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,177评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,732评论 3 229
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,953评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,687评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,263评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,189评论 2 258

推荐阅读更多精彩内容

  • 1.元类 1.1.1类也是对象 在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段。在Python中这...
    TENG书阅读 1,207评论 0 3
  • C++调用python 在C/C++中嵌入Python,可以使用Python提供的强大功能,通过嵌入Python可...
    Bruce_Szh阅读 13,511评论 1 7
  • http://python.jobbole.com/85231/ 关于专业技能写完项目接着写写一名3年工作经验的J...
    燕京博士阅读 7,475评论 1 118
  • 两本不错的书: 《Python参考手册》:对Python各个标准模块,特性介绍的比较详细。 《Python核心编程...
    静熙老师哈哈哈阅读 3,328评论 0 80
  • “丙申年腊月初,深冬极寒,有感于斯人,故作此阙。” 怨思长,两地相望,一处凄凉。梦回凝语泪私藏,谁...
    永生的王爵阅读 343评论 3 3