首先啊,我只学过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
指定函数可以被各个模块访问。