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

python数据分析源码_python 统计分析以后都在github更新,请参考CpythonInternals版本第一步克隆Cpython仓库到本地,切换到我当前的版本,我当前的版本号是3.8.0a0gitclonehttps://github.com/python/cpython.gitgitreset–hardab54b9a130c88f708077c2ef6c4963b632c132b…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

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

 

版本

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

git clone https://github.com/python/cpython.git
git reset --hard ab54b9a130c88f708077c2ef6c4963b632c132b3

PyObject

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

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.exe(或者在命令行里敲入 python) 的时候包括了上面的编译器和解释器的全部过程,上图只是做了一个抽象

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

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

a = 3
print(a)

之后命令行输入

python3 -m dis a.py

结果:

  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 行的位置

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行, 第一行和第五行:

PREDICTED(LOAD_CONST);
FAST_DISPATCH();

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

#define FAST_DISPATCH() goto fast_next_opcode
...
#define PREDICTED(op)           PRED_##op:

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

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 光纤及光纤接入设备[通俗易懂]

    光纤及光纤接入设备[通俗易懂]全面了解光纤接入设备及使用图解由于不同种类信息的需求也越来越多,伴随而来的不断增长的IP数据、话音、多媒体图像等多种新业务需求,促使了各大网络运营商的传送网络环境发生了翻天俯地的变化,以前那些以承载模拟话音为主要目的的传统城域网和接入网在容量以及接口种类上都已经无法满足多种多样的新业务传输与处理的要求。于是迫于社会信息量的突飞猛进,那些专门为城域网和接入…

  • 苹果备忘录导出到android,怎么把苹果的备忘录转到安卓系统?[通俗易懂]

    苹果备忘录导出到android,怎么把苹果的备忘录转到安卓系统?[通俗易懂]原标题:怎么把苹果的备忘录转到安卓系统?我的闺蜜小张之前一直使用的是苹果手机,她使用过苹果6s和iPhone8plus,不过最近这次在更换手机的时候,小张为了支持国产手机,就入手了一款华为手机。在试用了一两天的新华为手机后,小张表示这款华为手机也是比较好用的,于是小张就想把之前的苹果手机备忘录内容转到安卓系统中以便继续使用。彩色便签不过小张发现苹果自带备忘录内容是不支持授权一键导出所有数据的,这…

  • 海量数据处理面试题集锦

    海量数据处理面试题集锦十七道海量数据处理面试题与Bit-map详解作者:小桥流水,redfox66,July。前言   本博客内曾经整理过有关海量数据处理的10道面试题(十道海量数据处理面试题与十个方法大总结),此次除了重复了之前的10道面试题之后,重新多整理了7道。仅作各位参考,不作它用。   同时,程序员编程艺术系列将重新开始创作,第十一章以后的部分题目来源将取自下文中的17道海量数据处理的面试题。因为,我们觉

  • python跳出循环重新开始_python怎么跳出循环

    python跳出循环重新开始_python怎么跳出循环本文主要讲下python中的break语句用法,常用在满足某个条件,需要立刻退出当前循环时(跳出循环),break语句可以用在for循环和while循环语句中。简单的说,break语句是会立即退出循环,在其后边的循环代码不会被执行。break语句的用法>>>x=1>>>whileTrue:>>>x+=1>>>…

  • 文件上传linux文件名乱码_java导出文件名中文乱码

    文件上传linux文件名乱码_java导出文件名中文乱码从网上下了一个zip文件,unzip解压后发现中文显示都是乱码,以前也遇到过打开Windows系统下目录文件名也是乱码的问题。这是什么原因呢?文件是在Windows下创建的,而Windows的文件名中文编码默认GBK,Linux中默认文件名编码为UTF-8,编码不一致导致了文件名乱码的问题,解决这个问题需要对文件名进行转码,这个工具就是convmv。SYNOPSIS:convmv…

  • delphi打包python_Python for delphi教程

    delphi打包python_Python for delphi教程Related’PythonforDelphi’Linksonthissite:tutorial-Andy’sPythonDelphiTutorial-Gettingstartedwiththebasics.AlsousethesetechniquesifyouareusingDelphi5orbelow,andPyth…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号