python 中指针_Python源码学习笔记(二)PyTypeObject

c14199623a88ebde09cc4f107effd629.png

在前一篇讲PyObject的时候,有讲到PyObject中有一个指针,是指向PyTypeObject的,现在我们就来研究一下PyTypeObject的组成。

PyTypeObject的定义十分长,代码我们一部分一部分贴。

typedef struct _typeobject {
    /*看头部,发现_typeobject也是有PyObject头部*/
    PyObject_VAR_HEAD
    const char *tp_name; /* For printing, in format "<module>.<name>" */
    Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */

    /* 
     ...
    */
} PyTypeObject;

看第一部分,看到PyObject_VAR_HEAD。按照前一篇的说明,只要头部是PyObject_VAR_HEAD或者PyObject_HEAD的都可以看作PyObject的子类。但是这理解起来就有点费劲了。我们把PyObject_VAR_HEAD全部展开,得到。

Py_ssize_t ob_refcnt;               
struct _typeobject *ob_type;/*_typeobject的定义里有_typeobject指针*/        
Py_ssize_t ob_size;

看到了一个稍微有点费解的地方了。就是_typeobject里有_typeobject指针,这样会不会无限俄罗斯套娃呢?答案是当然不会了!这个案例在我们第一次学链表的时候就有了。想想是不是?

struct Node {
  Node* next;
};

在一个类型的声明里面包含这个类型的指针(注意,是指针),在C是允许的,毕竟指针就是一个地址变量。

tp_name在源代码中的注释就比较清楚了,就是用来打印的。

tp_basicsize和tp_itemsize是表明这个类型的一些空间大小的。至于设么是basicsize,什么是itemsize,我们之后在介绍其他对象的时候就会说到。

下一部分就是一些基础操作,看名字就很清晰大概是干嘛的了。比如tp_dealloc就是析构这个对象的时候会调用的函数。tp_print就是我们在python中print的时候会调用到的函数。

typedef struct _typeobject {
    /* 
     ...
    */
    /* Methods to implement standard operations */
    destructor tp_dealloc;
    printfunc tp_print;
    getattrfunc tp_getattr;
    setattrfunc tp_setattr;
    cmpfunc tp_compare;
    reprfunc tp_repr;
   /*
   ...
   */
} PyTypeObject;

但我们需要注意一点,这些都是函数指针,我们去看一看destructor这个宏看看,tp_dealloc是一个什么类型。

typedef void (*destructor)(PyObject *);

destructor是一个接受一个PyObject指针作为参数,并且无返回值的函数指针类型。接下来还有许多都是类似的声明,就不多说啦,都是类似的结构,至于每一种函数的作用目前我仍不能全说清楚。需要再多看一些其他类型的实现才能知道。

下一个部分。

typedef struct _typeobject {
    /* 
     ...
    */
    /* Method suites for standard classes */

    PyNumberMethods *tp_as_number;
    PySequenceMethods *tp_as_sequence;
    PyMappingMethods *tp_as_mapping;
   /*
   ...
   */
} PyTypeObject;

这三个指针就比较特别了,它们不是某一个函数指针,它们是结构体指针,指向啥呢?以PyNumberMethods举例。它里面包含了一堆函数,这些函数都是当我们使用这个PyObject的数值属性的时候会用到的函数。也就是tp_as_number的as_number的来由了。比如我们在python里输入1+1的时候,使用的就是nb_add进行操作了。

typedef struct {

    binaryfunc nb_add;
    binaryfunc nb_subtract;
    binaryfunc nb_multiply;
    binaryfunc nb_divide;
    binaryfunc nb_remainder;
    binaryfunc nb_divmod;
    ternaryfunc nb_power;
    /* 下面还有很多 ... */
    
} PyNumberMethods;

总结

总结一发。在Python源码中,我们基本可以这么认为,基础对象(int,float,string,list,dict这些),它的对象构成是类似的,无非在PyObject或PyVarObject的基础上增加新的属性。而具体的方法的区别都体现在其type object所声明的函数指针的具体实现上。

什么意思呢?就是同样是nb_add,不同类型的对象很可能就会有不同的实现,而这一切都是随其type object的改变而改变。


版权声明:本文为weixin_36309562原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。