首页 > 编程语言 >python解释器[源代码层面]

python解释器[源代码层面]

时间:2024-08-29 17:56:19浏览次数:12  
标签:解释器 co dk python PyCodeObject PyObject int ma 源代码

1 PyDictObject

在c++中STL中的map是基于 RB-tree平衡二元树实现,搜索的时间复杂度为O(log2n)

Python中PyDictObject是基于散列表(散列函数)实现,搜索时间最优为O(1)

1.1 散列列表

问题:散列冲突:多个元素计算得到相同的哈希值

解决方法:

(1)开链法

(2)开放地址法:二次探测法(python中用的)

通过增加一个二次函数形式的偏移量来查找下一个空闲位置。哈希表的大小为m,一个元素的初始位置由哈希函数 h(x)决定。若发生冲突,则将元素插入到位置 (h(x)+i^2)mod  m处,其中i是探测的步数。探测序列是一个二次序列,例如:1^2,(-1)^2,2^2,(-2)^2在表中寻找下一个可用位置。

从一个位置出发可依次到达多个位置,形成“冲突探测链”(注意删除链上元素导致的断链,采用伪删除技术。)

1.2 定义

typedef struct {
    /* Cached hash code of me_key. */
    Py_hash_t me_hash; //存储me_key的散列值,维护该值是避免每次查询时重新计算
    PyObject *me_key;
    PyObject *me_value; /* This field is only meaningful for combined tables */
} PyDictKeyEntry;

entry生存周期的四种状态

  1. unused态:me_key/me_value都是null(entry在初始化的时候)。
  2. Active态:entry存储了键值对的状态。
  3. Dummy态:me_key指向dummy对象(伪删除)。
  4. Pending态:键!=空,值=空(仅拆分),尚未插入到拆分表中。
/* The ma_values pointer is NULL for a combined table
 * or points to an array of PyObject* for a split table*/
typedef struct {
    PyObject_HEAD
    Py_ssize_t ma_used;    /*字典中项的数量*/
#ifdef Py_BUILD_CORE
    uint64_t ma_version_tag; /*表示字典中对象版本*/
#else
    Py_DEPRECATED(3.12) uint64_t ma_version_tag; /*表示字典中对象版本*/
#endif
    /*若ma_values为空,则表是结合的,键与值都存储在ma_keys中*/
    /*若ma_values不为空,则表是分开的,键存储在ma_keys中,值存储在ma_values*/
    PyDictKeysObject *ma_keys; /*实际存储数据的哈希表,具体有两种存储方式*/
    PyDictValues *ma_values; //根据两种存储方式决定是否有值
} PyDictObject;
struct _dictkeysobject {
    Py_ssize_t dk_refcnt;//引用计数器数目

    /* Size of the hash table (dk_indices). It must be a power of 2. */
    uint8_t dk_log2_size; //这张哈希表的大小(最大存储的元素的数目)

    /* Size of the hash table (dk_indices) by bytes. */
    uint8_t dk_log2_index_bytes; //哈希表大小的字节数

    /* Kind of keys */
    uint8_t dk_kind; //类型的键

    /* Version number -- Reset to 0 by any modification to keys */
    uint32_t dk_version; //版本号

    /* Number of usable entries in dk_entries. */
    Py_ssize_t dk_usable; //在dk_entries中可用的数量

    /* Number of used entries in dk_entries. */
    Py_ssize_t dk_nentries; //在dk_entries中使用的数量(8个字节)

    /* Actual hash table of dk_size entries. It holds indices in dk_entries,
       or DKIX_EMPTY(-1) or DKIX_DUMMY(-2).

       Indices must be: 0 <= indice < USABLE_FRACTION(dk_size).

       The size in bytes of an indice depends on dk_size:

       - 1 byte if dk_size <= 0xff (char*)
       - 2 bytes if dk_size <= 0xffff (int16_t*)
       - 4 bytes if dk_size <= 0xffffffff (int32_t*)
       - 8 bytes otherwise (int64_t*)

       Dynamically sized, SIZEOF_VOID_P is minimum. */
    char dk_indices[];  /* 索引,一个元素一个字节 */

    /* "PyDictKeyEntry or PyDictUnicodeEntry dk_entries[USABLE_FRACTION(DK_SIZE(dk))];" array follows:
       see the DK_ENTRIES() macro */
};

1.3 python3.6+的存储方法

  1. 第一条key-value,计算inx=hash(key)%num,num是索引表长,索引表中存放着对于enries的偏移量。
  2. 依据indices[inx]的值(偏移量)存放Hash value=hash(key)、key、value
  3. 若该位置已经有元素,则根据冲突解决策略找下一个空闲的索引。
  4. 查找键的时候同样流程,并比较键与值来确定是否需要所需元素。

---------------后续有必要再继续写---------------------------------------------------

2 解释器

2.1组成

编译器:得到字节码的编译结果(import py文件、import compileall、内建函数compile后会得到.pyc文件)

虚拟机:执行字节码

执行环境:字典对象,维护运行过程中动态创建的变量和变量名与变量值的映射。

2.2执行脚本流程

1.完成模块的加载和链接

2.将源代码编译为PyCodeObject对象,并将其写入内存,使得CPU快速读取,加快程序运行

注:字节码与PyCodeObject对象的关系?

        PyCodeObject对象包含字符串,常量值,操作(字节码)等静态信息(运行时存储在PyCodeObject对象中,运行结束后存储在pyc文件)

3.从内存空间中读取指定并执行(虚拟机完成)

编译器与虚拟机在:python .dll

4.程序结束后根据调用的操作指令决定是否也将PyCodeObject对象写入硬盘,即.pyc文件或.pyo文件。

5.下一次再执行该脚本,则先检查本地是否有上述.pyc文件。如有,则执行。

2.3PyCodeObject

struct PyCodeObject{                                                    \
    PyObject_VAR_HEAD                                                          \
                                                                               \
    /* Note only the following fields are used in hash and/or comparisons      \
     *                                                                         \
     * - co_name                                                               \
     * - co_argcount                                                           \
     * - co_posonlyargcount                                                    \
     * - co_kwonlyargcount                                                     \
     * - co_nlocals                                                            \
     * - co_stacksize                                                          \
     * - co_flags                                                              \
     * - co_firstlineno                                                        \
     * - co_consts                                                             \
     * - co_names                                                              \
     * - co_localsplusnames                                                    \
     * This is done to preserve the name and line number for tracebacks        \
     * and debuggers; otherwise, constant de-duplication would collapse        \
     * identical functions/lambdas defined on different lines.                 \
     */                                                                        \
                                                                               \
    /* These fields are set with provided values on new code objects. */       \
                                                                               \
    /* The hottest fields (in the eval loop) are grouped here at the top. */   \
    PyObject *co_consts;           /* list (constants used) */                 \
    PyObject *co_names;            /* list of strings (names used) */          \
    PyObject *co_exceptiontable;   /* Byte string encoding exception handling  \
                                      table */                                 \
    int co_flags;                  /* CO_..., see below */                     \
                                                                               \
    /* The rest are not so impactful on performance. */                        \
    int co_argcount;              /* #arguments, except *args */               \
    int co_posonlyargcount;       /* #positional only arguments */             \
    int co_kwonlyargcount;        /* #keyword only arguments */                \
    int co_stacksize;             /* #entries needed for evaluation stack */   \
    int co_firstlineno;           /* first source line number */               \
                                                                               \
    /* redundant values (derived from co_localsplusnames and                   \
       co_localspluskinds) */                                                  \
    int co_nlocalsplus;           /* number of local + cell + free variables */ \
    int co_framesize;             /* Size of frame in words */                 \
    int co_nlocals;               /* number of local variables */              \
    int co_ncellvars;             /* total number of cell variables */         \
    int co_nfreevars;             /* number of free variables */               \
    uint32_t co_version;          /* version number */                         \
                                                                               \
    PyObject *co_localsplusnames; /* tuple mapping offsets to names */         \
    PyObject *co_localspluskinds; /* Bytes mapping to local kinds (one byte    \
                                     per variable) */                          \
    PyObject *co_filename;        /* unicode (where it was loaded from) */     \
    PyObject *co_name;            /* unicode (name, for reference) */          \
    PyObject *co_qualname;        /* unicode (qualname, for reference) */      \
    PyObject *co_linetable;       /* bytes object that holds location info */  \
    PyObject *co_weakreflist;     /* to support weakrefs to code objects */    \
    _PyCoCached *_co_cached;      /* cached co_* attributes */                 \
    uint64_t _co_instrumentation_version; /* current instrumentation version */  \
    _PyCoMonitoringData *_co_monitoring; /* Monitoring data */                 \
    int _co_firsttraceable;       /* index of first traceable instruction */   \
    /* Scratch space for extra data relating to the code object.               \
       Type is a void* to keep the format private in codeobject.c to force     \
       people to go through the proper APIs. */                                \
    void *co_extra;                                                            \
    char co_code_adaptive[(SIZE)];                                             \
}

1.一个命名空间对应一个PyCodeObject对象。

2.类、函数、module都对应一个独立的命名空间(存在嵌套关系)。

2.4pyc文件

pyc文件=magic number( 区别python版本)+pyc文件的最后一次修改时间(再次加载时判断是否修改过)+PyCodeObject对象。

2.5创建pyc文件的具体过程(把PyCodeObject对象写入文件)

-------------------------待写

标签:解释器,co,dk,python,PyCodeObject,PyObject,int,ma,源代码
From: https://blog.csdn.net/weixin_46115467/article/details/141643213

相关文章

  • python读取配置文件&&简单封装 公共配置文件 config
    之前有做过把爬虫数据写到数据库中的练习,这次想把数据库信息抽离到一个ini配置文件中,这样做的好处在于可以在配置文件中添加多个数据库,方便切换(另外配置文件也可以添加诸如邮箱、url等信息)1.configparser模块python使用自带的configparser模块用来读取配置文件,配置文......
  • 分享4大主流 Python IDE,助力你高效编写Python代码
    Python作为一门简洁易学、功能强大的编程语言,在各个领域都展现出了强大的魅力。而选择一款合适的IDE,则是提高Python开发效率的关键。本文将带你深入了解4大主流PythonIDE:PyCharm、Spyder、JupyterNotebook、VSCode,帮助你找到最适合自己的开发利器。PyCharm:专业开发......
  • python Pandas合并(单元格、sheet、excel )
    如果你对Python感兴趣的话,可以试试我整理的这一份全套的Python学习资料,【点击这里】免费领取!安装Pandas和openpyxl首先,确保已经安装了Pandas和openpyxl。可以通过pip安装:pip install pandas openpyxl创建DataFrameimportpandasaspd#创建DataFramed......
  • 总结24个Python接单赚钱的平台,总有适合你的,兼职月入5000+
    这里为大家整理了24个Python接私活的平台,另外还有一些接私活的注意事项。当然这些平台不止Python语言能接单,事实上基本所有语言都能找到合适的单子~温馨提示:1.没有第三方担保的个人单,风险较大尽量少接2.无需求文档,讲不清具体需求的不接3.没有预付的不做,结款方式按442的方式......
  • python接口自动化——接口登录获取session、cookie
    【参考】方法一参考链接如下,直接获取返回的cookie失败,拿到的cookies是空。(因为登录的url返回用f12看着是空的,用Charles才能看到,进行了重定向,返回了重定向的url)https://baijiahao.baidu.com/s?id=1781328761925882355&wfr=spider&for=pc 方法二参考链接如下,去拿session,再使用s......
  • 使用Flask快速构建Web后端项目:Python、Flask、Mysql、Migrate、SQLAlchemy、Login、Se
    Flask是一个用Python编写的轻量级Web应用框架。它设计简单且易于扩展,如果与Jinja2模板引擎和WerkzeugWSGI工具集结合使用,Flask可以用来快速开发小型到中型的网站。Flask鼓励快速开发和简洁的代码,同时保持了扩展性和灵活性。本文旨在如何使用Flask及其相关组件快......
  • python基础个人笔记
    一、基础变量    可使用type(param)查看变量类型    1.整型int         可使用int(param)强转    2.浮点型float                可使用float(param)强转    3.复数complex       ......
  • python打包exe文件注意事项
    1.进入虚拟环境一开始使用pipenvshell,后续可以使用conda。使用虚拟环境可以尽量减小软件包的大小,减少不相关包的引入。2.当前环境目录中不要有__init__.py因为,打包时很可能被当为环境,不再打包其他文件。3.制作main.spec安装pyinstaller包,配置你的exe的icon。pipinstal......
  • Python可控制线程与TCP服务单元编程
    大家好,我之前在我的CSDN博客上面发了一条《C++可控制线程》的文章,里面介绍了在线程中植入类似状态机的东西,进而将多线程编程进化为“服务单元”编程的技术。接下来我们来看一个基于此项目的Python的TCP服务单元代码。------------------------------------------------------......
  • 【Python】将网格数据写入到VTK文件
    1.vtk文件格式根据官网进行总结vtk文件组成:5个部分.第一部分,第一行:表明文件版本.写"#vtkDataFileVersion2.0"就行第二部分,第二行:表明标题(title).随便写.第三部分,第三行:ASCII或者BINARY第四部分,开始定义datasetstructure.这部分用于描述数据集的几何和拓扑......