CPython开启自毙之旅

首先啊,我只学过C. 其次,我只在大一的时候学过C. 最后,我更爱Rust.

但是我也很喜欢Python。 所以说,自虐吧, CPython源码阅读计划开启:

参考博客:https://www.cnblogs.com/traditional/p/13655426.html

我们可以import调用,但是在Python安装目录里面则是看不到的。像这种底层由C编写、内嵌在解释器里面的模块,以及那些无法使用文本打开的pyd文件,pycharm都会给你做一个抽象,并且把注释给你写好。

Python源码中的Modules目录,这个目录里面存放了大量使用C编写的模块,我们在编译完Python之后就,这些模块就内嵌在解释器里面了。而这些模块都是针对那些性能要求比较高的,而要求不高的则由Python编写,存放在Lib目录下。像我们平时调用random、collections、threading,其实它们背后会调用_random、_collections、_thread。再比如我们使用的re模块,真正用来做正则匹配的逻辑实际上位于 *Modules/_sre.c* 里面而跟编译器相关的一些头文件一般都在Include文件夹下面。核心代码在Include/internal下面的哪些头文件中定义了主要的数据结构,看了一天好不容易捋了捋文件的脉络,太不容易了呜呜呜。

先了解一些基本文件: Include/pytypedefs.h 等量定义了超级一部分的Python模块对象,新的Py打头的结构体优先考虑在这里面寻找

类:

首先看看Python对象的核心PyObject:

// 在pytyprdefs.h 文件中使用typeof做了等价定义,也就是Pyobjects与_object等价
typedef struct _object PyObject;
typedef struct _typeobject PyTypeObject;

//(Include/) object.h
struct _object {
    _PyObject_HEAD_EXTRA    // 这是一个宏定义的相当于Null或两个,两个(指向前面和后面) PyObject/self结构体的指针
    Py_ssize_t ob_refcnt;   // 垃圾回收机制的引用计数器,一个有符号整形
    PyTypeObject *ob_type;  // 类的类型定义
};

// 第一个参数宏的定义:
// 如果定义了说明之前使用过相同的类,参考https://blog.csdn.net/weixin_42511320/article/details/106037958
// 在Python中创建的所有类都会放进refchain的环(双向链表)中。在只有一个类或没有类的时候不需要前后指针,但是一旦由两个以上的类的时候就要用指针吧这些类连起来
// 
#ifdef Py_TRACE_REFS
/* Define pointers to support a doubly-linked list of all live heap objects. */
#define _PyObject_HEAD_EXTRA            \
// 定义两个指针,一个指向前一个定义的类,一个指向后一个定义的类(双向链表)
    PyObject *_ob_next;           \
    PyObject *_ob_prev;

#define _PyObject_EXTRA_INIT _Py_NULL, _Py_NULL,

#else
// 没定义就暂时不需要
#  define _PyObject_HEAD_EXTRA
#  define _PyObject_EXTRA_INIT
#endif


// 第二个参数类型定义:
// include/pyport.h
// 他和ssizt_t是同一类型的,ssize_t应该手洗的人会多一些,是C的嵌入类型。
// 有符号整形。表示可以被执行读写操作的数据块的大小.它和size_t类似,但必需是signed
typedef ssize_t Py_ssize_t;



// 第三个参数定义,非常的长,并且有一堆没在本文件中定义的宏和参数,真的让人看的想骂人。
//Include/cpython/object.h
struct _typeobject {
    // 第一个define定义的宏, Include/objects
    // #define PyObject_VAR_HEAD      PyVarObject ob_base;
    // 这个PyVarObject就是_object/PyObject多加了一个size属性。这个size也是Py_ssize_t类型,不过确实是表示大小用的
    // 有了size, 就说明大小可变。对于需要变换大小的对象来说这是不可或缺的
    PyObject_VAR_HEAD
        
    // 类的名字
    const char *tp_name; /* For printing, in format "<module>.<name>" */
    // 创建实例对象时候所需要的内存信息,应该是类本身 + 对象属性两个部分
    Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */

    /* Methods to implement standard operations */
	
    // 实例对象进行构析函数时候进行的操作
    // deatructor也是在Include/objects.h中定义的
    //typedef void (*destructor)(PyObject *);
    destructor tp_dealloc;
    Py_ssize_t tp_vectorcall_offset;
    // 这两个是甚至于获取参数,定义在Include/object.h中
    //typedef PyObject *(*getattrfunc)(PyObject *, char *);
    //typedef int (*setattrfunc)(PyObject *, char *, PyObject *);
    // 这个定义其实是定义了函数指针,具体可见下面
    // 所以这里是向结构体里面塞了方法。塞了返回PyObject指针的两个方法,可以被赋值为相应的方法
    getattrfunc tp_getattr;
    setattrfunc tp_setattr;
    // 又一个结构体,不过是在同级文件中,定义如下,会在下介绍这个结构体
    PyAsyncMethods *tp_as_async; /* formerly known as tp_compare (Python 2)
                                    or tp_reserved (Python 3) */
    reprfunc tp_repr;

    /* Method suites for standard classes */
	//给一些基本类型定义的方法,比如NumberMethod定义了加减绝对值等等
    PyNumberMethods *tp_as_number;
    PySequenceMethods *tp_as_sequence;
    PyMappingMethods *tp_as_mapping;

    hashfunc tp_hash;
    ternaryfunc tp_call;
    reprfunc tp_str;
    getattrofunc tp_getattro;
    setattrofunc tp_setattro;

    /* Functions to access object as input/output buffer */
    // 包含了发你配空间于释放空间的方法
    PyBufferProcs *tp_as_buffer;

    /* Flags to define presence of optional/expanded features */
    unsigned long tp_flags;
	
    // 接受__doc__方法的定义类似的东西
    const char *tp_doc; /* Documentation string */

    /* Assigned meaning in release 2.0 */
    /* call function for all accessible objects */
    traverseproc tp_traverse;

    /* delete references to contained objects */
    // 这里是说删除引用。我不知道咋删除的,但是定义长这样
    //typedef int (*inquiry)(PyObject *);
    inquiry tp_clear;

    /* Assigned meaning in release 2.1 */
    /* rich comparisons */
    richcmpfunc tp_richcompare;

    /* weak reference enabler */
    Py_ssize_t tp_weaklistoffset;

    /* Iterators */
    // 相当于迭代器一类的定义,适合内中可迭代对象大概
    getiterfunc tp_iter;
    iternextfunc tp_iternext;

    /* Attribute descriptor and subclassing stuff */
    // 类里面包含方法的嘛,剩下的可以按照名字来理解,无需完全看定义方法的
    PyMethodDef *tp_methods;
    PyMemberDef *tp_members;
    PyGetSetDef *tp_getset;
    // Strong reference on a heap type, borrowed reference on a static type
    // 
    PyTypeObject *tp_base;
    PyObject *tp_dict;
    descrgetfunc tp_descr_get;
    descrsetfunc tp_descr_set;
    Py_ssize_t tp_dictoffset;
    initproc tp_init;
    allocfunc tp_alloc;
    newfunc tp_new;
    freefunc tp_free; /* Low-level free-memory routine */
    // GC回收查看帆帆发,反正是int型函数,估计是查看自身引用计数的方法
    inquiry tp_is_gc; /* For PyObject_IS_GC */
    PyObject *tp_bases;
    PyObject *tp_mro; /* method resolution order */
    PyObject *tp_cache;
    PyObject *tp_subclasses;
    PyObject *tp_weaklist;
    destructor tp_del;

    /* Type attribute cache version tag. Added in version 2.6 */
    unsigned int tp_version_tag;

    destructor tp_finalize;
    vectorcallfunc tp_vectorcall;
};



// 上面type_object中涉及到类型的结构体
typedef struct {
    // 看这个架势应该是四个函数指针定义的函数哦
    // 果然,还是在Include/objects.h中定义的
    // typedef PyObject * (*unaryfunc)(PyObject *);
    // 这几个变量名字比较暧昧,再加上只有这种函数指针真的说明不了什么,在后面会补上这些函数的赋值
    unaryfunc am_await;
    unaryfunc am_aiter;
    unaryfunc am_anext;
    sendfunc am_send;
} PyAsyncMethods;
//关于上面说的typedef int (*setattrfunc)(PyObject *, char *, PyObject *)函数方法指针
// 举个例子
// tests是一个函数类型,参数为int型指针于char型指针, 并返回int指针的这样一个函数
// 所以上面的意思大概差不多,主要是在结构体里防止一些方法罢了
// 顺带提一句这里int * 后面有没有参数名都无所谓。
typedef  int *(*tests)(int *, char* );
int * hello(int *a, char *c){
    printf("%d, %s", *a, c);
    return a;
}
int main() {
    tests a = hello;
    int d[5] = {3,5,4,2,1, };
    int *b = d;
    int *h = a(b,"Hello  ");
    while (*h != 1){
        printf("%d", *h);
        h += 1;
    }
}
3, Hello  3542
typedef struct {
    PyObject ob_base;
    Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;
//PyVarObject比PyObkect加了里面涵盖的对象个数的属性

之后类的头文件包括了一堆的static inline函数,定义了一些基本的get, set方法,这就是纯C的类么爱了爱了

//一些其他的琐碎笔记:
// 引用计数器_PyObject_HEAD_EXTRA定义宏
// Include/object.h
#ifdef Py_TRACE_REFS
/* Define pointers to support a doubly-linked list of all live heap objects. */
#define _PyObject_HEAD_EXTRA            \
    PyObject *_ob_next;           \
    PyObject *_ob_prev;

// 常量null (,_Py_NULL是 null_Ptr类型) 或者为空?,嗷,毕竟是初始化头部,可以理解
#define _PyObject_EXTRA_INIT _Py_NULL, _Py_NULL,

#else
#  define _PyObject_HEAD_EXTRA
#  define _PyObject_EXTRA_INIT
#endif



// 所以这个是强制类型转换函数,把op强转为PyObject指针的函数
#define _PyObject_CAST(op) _Py_CAST(PyObject*, (op))
#define _PyVarObject_CAST(op) _Py_CAST(PyVarObject*, (op))

// 使用Py_Type判断类的方法是是否能强转,大吃我一惊
#  define Py_TYPE(ob) Py_TYPE(_PyObject_CAST(ob))


具体顺序应该是cpython/object.h定义 -》 Include下面其他文件define这些东西多添加几个名字 =》 在Include/object.h中使用。

    

然后是一堆的PyAPI_FUNC 真的,这个东西是啥玩应,宏么,找不到定义ORZ, 在经历了痛苦的查找后得到了这样的结论(来源自https://blog.csdn.net/qq_31896123/article/details/111157465)

定义了一个公开的可以被其它模块调用或重写的函数``

结论:PyAPI_FUNC 指定函数可以被各个模块访问。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值