专栏首页Pulsar-VPython内核源码解析与C/CPP-API拓展编程(一)PyObject

Python内核源码解析与C/CPP-API拓展编程(一)PyObject

下载Python源码

我这里使用Python3.5作为学习的源码

目录结构

|
--- Include: 包括Python提供的所有头文件, 可以用于c/c++扩展
--- Lib: Python的标准库, 全部都是用python写的
--- Modules: 包含了C语言编写的模块, 比如random, StringIO 等
--- Parser: 包含了python解释器中的scanner和parser部分,也就是词法分析和语法分析部分,一个类似yacc一样根据规则自动生成
--- Objects: 包含所有Python的内置对象,整数, list, dict等.也包含了运行时python需要的所有内部使用的对象的实现
--- Python: 包含了python解释器中Compiler和执行引擎部分,是python运行的核心所在
--- PCBuild:包含了vs工程文件

调试方法:

基于C++的调试对于已经到Python虚拟机中存储起来的字节码命令是无法被观察到的,我们只能把它们解析成AST才能看懂字节码在解释器内存中的状态,所以这里我们借用Python解释器里的C_API来输出我们的对象:

PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int);

# eg:
PyObject_Print(v, stdout, 0);

Python架构

Python的整体架构可分为3个模块

  1. 内建模块 Python提供的大量的模块、库以及用户自定义的模块,比如import math,math就是python的内建模块。
  2. Python的运行时环境,包括对象/类型系统(Object/Type structures)、内存分配器(Memory Allocator)和运行时状态信息(Current State of Python)。 对象/类型系统:包含Python中存在的各种内建对象,int、list、dict等,以及用户自定义的各种类型和对象。
  • 内存分配器:负责Python中创建对象时,对内存的申请工作,实际上是Python运行时与C中malloc的一层接口。
  • 运行时状态:维护了解释器在执行字节码时不同的状态(正常状态和异常状态)之间的切换,有穷状态机。
  1. Python解释器或称为虚拟机,包括Scanner词法分析器,Parser语法分析器 ,Compiler编译器,Code Evaluator虚拟机。
  • Scanner:将输入的Python源代码或从命令输入的Python代码分割成一个个的token。
  • Parser:在Scanner的分析结果上进行语法分析,建立抽象语法树(AST)。
  • Compiler:根据建立的AST生成指令集合—-Python字节码(byte code)
  • Code Evaluator:执行字节码。

PyObject

python玩家都知道,在python中,万物皆对象,python的源码中是通过下面的代码去定义每一个对象的。 object.h

typedef struct _object {
    _PyObject_HEAD_EXTRA
    Py_ssize_t ob_refcnt;
    struct _typeobject *ob_type;
} PyObject;

结构体中包含了Py_ssize_t、_typeobject两个成员,下面一个个来看它的成员的定义和意义。

_PyObject_HEAD_EXTRA

object.h

#ifdef Py_TRACE_REFS
/* Define pointers to support a doubly-linked list of all live heap objects. */
#define _PyObject_HEAD_EXTRA            \
    struct _object *_ob_next;           \
    struct _object *_ob_prev;

#define _PyObject_EXTRA_INIT 0, 0,

#else
#define _PyObject_HEAD_EXTRA
#define _PyObject_EXTRA_INIT
#endif

Py_ssize_t

往下检索可以看到定义 pyport.h

typedef Py_intptr_t     Py_ssize_t;

pyport.h

typedef intptr_t        Py_intptr_t;

vcstdint.h

//预编译判断操作系统类型
#ifdef _WIN64 // [如果是64位操作系统
   typedef __int64           intptr_t;
   typedef unsigned __int64  uintptr_t;
#else // _WIN64 ][32位操作系统
   typedef _W64 int               intptr_t;
   typedef _W64 unsigned int      uintptr_t;
#endif // _WIN64 ]

__w64是一个编译器相关的关键字, 意思是说这个类型使用64位兼容方式编译, 在编译64位程序时指针就被视为64位宽, 而不是32位. int也有可能会被视为64位. __int64 原形为

typedef int __w64 __int64

换句话说在64位系统中, 它是64位int整型, 32位系统就是int. _W64 是为了兼容64位系统存在的. 所以 Py_ssize_t 的本质就是 int类型的变量。 将上面的定义全部回带化简以后,代码变成

typedef struct _object {
    __int64 ob_refcnt;//int ob_refcnt
    struct _typeobject *ob_type;
} PyObject;
作用

表示变量引用次数, python的垃圾回收机制基于引用计数, 在python运行的过程中当某个对象引用计数减少到0时, 就可以将该变量从堆上删除,释放内存。我们可以检索到引用计数的处理定义。

#define Py_INCREF(op)   ((op)->ob_refcnt++)          //增加计数
#define Py_DECREF(op)      \                         //减少计数        
     if (--(op)->ob_refcnt != 0)    \
         ;        \
     else         \
         __Py_Dealloc((PyObject *)(op))

引用计数为0时,该对象生命周期结束,python释放内存。

  • 引用计数机制的优点:
  1. 简单
  2. 实时性:一旦没有引用,内存就直接释放了。不用像其他机制等到特定时机。实时性还带来一个好处:处理回收内存的时间分摊到了运行时。
  • 引用计数机制的缺点:
  1. 维护引用计数消耗资源
  2. 循环引用

好了到此为止,涉及python的垃圾回收(GC)后面专门会分一篇文章来讲解

_typeobject

表示了对象的类型信息, 诸如int, string, function,class等,这里做一个简述,具体细节留到下一篇python类型对象去写。

(adsbygoogle = window.adsbygoogle || []).push({});

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • C++随笔(二)用指针强制访问private的值

    private本来是私有变量,外部无法访问的,但是抖个机灵,我们用指向类的指针和在类里面不断偏移我们的指针地址来访问私有成员变量的值。

    Pulsar-V
  • C++随笔(一)关于用int来表示一个对象指针并复原问题

    昨天群里一个老哥问我的,他去取了一个线程的DWORD地址,然后保存成为一个char* buffer,在接下来的使用过程中,把buffet内存储的指针地址赋值给一...

    Pulsar-V
  • Matlab 航模挂载设计

    题目 航模组决定对某款航模的挂载能力进行改造测试,希望获得最大的飞行性能评价值。航模挂载设备的体积V(单位:cm3)和重量M(单位:g)均会影响飞行性能评价值,...

    Pulsar-V
  • 简易 bokeh 图像散景效果算法实现

    bokeh百度百科的解释 摄影镜头光圈大小和拍摄距离决定了拍摄时的景深,相对于焦点位置,焦点前与焦点后的被拍摄物体会显得模糊,这个模糊区域被称为焦外。 焦外...

    cpuimage
  • 【CodeForces706E】Working routine(二维链表)

    q次操作,每次把两个给定子矩阵交换,求最后的矩阵。(2 ≤ n, m ≤ 1000, 1 ≤ q ≤ 10 000)

    饶文津
  • 种树 差分约束|贪心

    每次种的树在重叠区间越多,种的树越少。只有结束位置才会重合,就对区间结束的位置从小到大排序。

    用户2965768
  • 常见的五种排序算法

    冒泡排序只会操作相邻的两个数据。每次冒泡操作都会对相邻的两个元素进行比较,看是否满足大小关系要求。

    Yif
  • 传统高斯模糊与优化算法(附完整C++代码)

    高斯模糊(英语:Gaussian Blur),也叫高斯平滑,是在Adobe Photoshop、GIMP以及Paint.NET等图像处理软件中广泛使用的处理效果...

    cpuimage
  • Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 2) C. Connect(bfs)

    题目链接:http://codeforces.com/contest/1130/problem/C

    Ch_Zaqdt
  • Java常用排序算法/程序员必须掌握的8大排序算法

    1)插入排序(直接插入排序、希尔排序) 2)交换排序(冒泡排序、快速排序) 3)选择排序(直接选择排序、堆排序) 4)归并排序 5)分配排序(基数排序)

    哲洛不闹

扫码关注云+社区

领取腾讯云代金券