前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python数据分析源码_python 统计分析

python数据分析源码_python 统计分析

作者头像
全栈程序员站长
发布2022-09-24 07:44:03
5350
发布2022-09-24 07:44:03
举报

大家好,又见面了,我是你们的朋友全栈君。

以后都在 github 更新,请参考 Cpython Internals

版本

第一步克隆 Cpython 仓库到本地, 切换到我当前的版本, 我当前的版本号是 3.8.0a0

代码语言:javascript
复制
git clone https://github.com/python/cpython.git
git reset --hard ab54b9a130c88f708077c2ef6c4963b632c132b3

PyObject

PyObject 是 cpython 源码中最基本的 python 对象,记录了单个 Python 对象的任何信息, 他们的 memory layout 如下所示

python数据分析源码_python 统计分析
python数据分析源码_python 统计分析

_PyObject_HEAD_EXTRA 在 Include/object.h 中第 72-83 行, 如果定义了 Py_TRACE_REFS 这个 marco, 他就是一对链表指针,指向上一个对象和下一个对象,不然的话(默认情况下),他就是一个空的值,猜测是 debug 或者其他特殊情况下开启这个选项

ob_refcnt 是引用计数器,类型应该是一个无符号整型, 在cpython中垃圾回收中发挥作用,关于cpython的垃圾回收机制可以参考 python3 的垃圾回收机制

ob_type 是真正指向这个 python 对象的指针,你看到的 tp_name, tp_print, getattr, setattr 等 python 对象共有的属性都能在这里找到

Ceval

执行一个 .py 文件会经历如下过程

python数据分析源码_python 统计分析
python数据分析源码_python 统计分析

其实 ./python.exe(或者在命令行里敲入 python) 的时候包括了上面的编译器和解释器的全部过程,上图只是做了一个抽象

编译器将 py 文件转换成 python byte code(字节码), 里面是一个一个的 python 虚拟机指令

比如新建下面的文件 a.py

代码语言:javascript
复制
a = 3
print(a)

之后命令行输入

代码语言:javascript
复制
python3 -m dis a.py

结果:

代码语言:javascript
复制
  1           0 LOAD_CONST               0 (3)
              2 STORE_NAME               0 (a)

  2           4 LOAD_NAME                1 (print)
              6 LOAD_NAME                0 (a)
              8 CALL_FUNCTION            1
             10 POP_TOP
             12 LOAD_CONST               1 (None)
             14 RETURN_VALUE

左边的 1 和 2 是 第一行和第二行的意思,a.py 总共只有两行代码,所以只能看到 1 和 2

中间的是这一行是每一行代码对应的 python byte code

参考 Include/opcode.h 发现总共有 121 个 opcode, 所有的 python 源文件都会在内存中被编译器翻译成由 opcode 组成字节码指令集, 而 import 目录下会被保存成 pyc 文件,并缓存在执行目录,下次启动程序如果源代码没有修改过,则直接加载这个pyc文件,这个文件的存在可以加快 python 的加载速度

在 python 虚拟机中,解释器主要在一个很大的循环中,不停地读入 opcode, 并根据 opcode 执行对应的指令,当执行完所有指令虚拟机退出,程序也就结束了,这个主要的循环在 ceval.c 中,第 922 行的位置

代码语言:javascript
复制
main_loop:
    for (;;) {
        ...
            
        switch (opcode) {

        /* BEWARE!
           It is essential that any operation that fails must goto error
           and that all operation that succeed call [FAST_]DISPATCH() ! */

        case TARGET(NOP): {
            FAST_DISPATCH();
        }

        case TARGET(LOAD_FAST): {
            PyObject *value = GETLOCAL(oparg);
            if (value == NULL) {
                format_exc_check_arg(PyExc_UnboundLocalError,
                                     UNBOUNDLOCAL_ERROR_MSG,
                                     PyTuple_GetItem(co->co_varnames, oparg));
                goto error;
            }
            Py_INCREF(value);
            PUSH(value);
            FAST_DISPATCH();
        }

        case TARGET(LOAD_CONST): {
            PREDICTED(LOAD_CONST);
            PyObject *value = GETITEM(consts, oparg);
            Py_INCREF(value);
            PUSH(value);
            FAST_DISPATCH();
        }
        ...
    }
}

可以看到这个循环

我们来简单看下 LOAD_CONST 这个指令, 在上面的 switch case 里面,这个指令的代码总共5行, 第一行和第五行:

代码语言:javascript
复制
PREDICTED(LOAD_CONST);
FAST_DISPATCH();

在 ceval.c 第 732 行可以找到 PREDICTED 的定义, 第 666 行可以找到 FAST_DISPATCH 的定义

代码语言:javascript
复制
#define FAST_DISPATCH() goto fast_next_opcode
...
#define PREDICTED(op)           PRED_##op:

## 和 # 号在 marco 里的作用可以参考 这篇

所以 LOAD_CONST 这个指令展开之后如下

代码语言:javascript
复制
case TARGET(LOAD_CONST): {
    PRED_LOAD_CONST:
    PyObject *value = GETITEM(consts, oparg);
    Py_INCREF(value);
    PUSH(value);
    goto fast_next_opcode;
}

可以看到,这个指令通过 GETITEM 从 oparg 中获取到了一个 python 对象的指针,这个指针的类型是 PyObject *

Py_INCREF 作用是把这个 PyObject * 对象的引用计数器加一, 关于引用计数器可以参考 python3 的垃圾回收机制

PUSH 的作用是把这个刚刚创建的 PyObject * push 到 当前的 frame 的 stack 上面,以便下一个指令从这个 stack 上面获取

关于 frame 可以参考 cpython 源码分析 PyFrameObject

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/172354.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 版本
  • PyObject
  • Ceval
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档