python源码

python源码在安装路径下可找到
image

  • include: 包含了python所提供的所有头文件,都使用c编写
  • lib: 包含了python自带的所有标准库,都使用python编写
  • parse:包含python解释器中的Parse部分
    ps:其他的不太清楚了,有知道的朋友还望留言使我补拙。

python程序执行过程

python虚拟机(解释器)先会对.py静态文件进行编译为字节码,存在内存的PyCodeObject对象中,当程序运行结束后,PyCodeObject对象中的内容会存在.pyc中。当程序下次运行的时候,python会从.pyc中记录的内容直接构建内存中的PyCodeObject对象,而不会再次编译。
换言之:PyCodeObject与.pyc是python程序字节码的不同表现形式。

image
上图中,python(版本).dll就是python的虚拟机(解释器)。(在python安装目录下可看到)

python源码中的PyCodeObject

[code.h]

/* Bytecode object */
typedef struct {
    PyObject_HEAD
    int co_argcount;            /* #arguments, except *args */
    int co_posonlyargcount;     /* #positional only arguments */
    int co_kwonlyargcount;      /* #keyword only arguments */
    int co_nlocals;             /* #local variables */
    int co_stacksize;           /* #entries needed for evaluation stack */
    int co_flags;               /* CO_..., see below */
    int co_firstlineno;         /* first source line number */
    PyObject *co_code;          /* instruction opcodes */
    PyObject *co_consts;        /* list (constants used) */
    PyObject *co_names;         /* list of strings (names used) */
    PyObject *co_varnames;      /* tuple of strings (local variable names) */
    PyObject *co_freevars;      /* tuple of strings (free variable names) */
    PyObject *co_cellvars;      /* tuple of strings (cell variable names) */
    /* The rest aren't used in either hash or comparisons, except for co_name,
       used in both. 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.
    */
    Py_ssize_t *co_cell2arg;    /* Maps cell vars which are arguments. */
    PyObject *co_filename;      /* unicode (where it was loaded from) */
    PyObject *co_name;          /* unicode (name, for reference) */
    PyObject *co_lnotab;        /* string (encoding addr<->lineno mapping) See
                                   Objects/lnotab_notes.txt for details. */
    void *co_zombieframe;       /* for optimization only (see frameobject.c) */
    PyObject *co_weakreflist;   /* to support weakrefs to code objects */
    /* 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;

    /* Per opcodes just-in-time cache
     *
     * To reduce cache size, we use indirect mapping from opcode index to
     * cache object:
     *   cache = co_opcache[co_opcache_map[next_instr - first_instr] - 1]
     */

    // co_opcache_map is indexed by (next_instr - first_instr).
    //  * 0 means there is no cache for this opcode.
    //  * n > 0 means there is cache in co_opcache[n-1].
    unsigned char *co_opcache_map;
    _PyOpcache *co_opcache;
    int co_opcache_flag;  // used to determine when create a cache.
    unsigned char co_opcache_size;  // length of co_opcache.
} PyCodeObject;

image

python编译器再对python编译的时候,对于代码中的一个Code Block会创建一个PyCodeObject对象与这段代码对应,那么如何确定多少代码算是一个Code Block呢?事实上,python有一个简单而清晰的规则:当进入一个新的名字空间,或者说作用域时,我们就算是进入了一个新的Code Block了。

比如对于下面这个demo,编译完之后总共会创建3个PyCodeObject对象,一个是对应demo.py整个文件的,一个是对应class A所代表的Code Block,而最后一个是对应 def func所代表的Code Block。
image

使用 python -m compileall 命令会编译当前目录中的所有.py文件。

pyc文件

每一个PyCodeObject对象中都包含了每一个Code Block中所有的python源代码经过编译后得到的byte code序列,前面有提到,python会将这些字节码序列和PyCodeObject对象一起存储在.pyc文件中,但是不幸的是,事实并不是总是这样。在命令行执行以下python demo.py会发现并没有产生一个对应的pyc文件。为什么呢?真实的原因不得而知,不过我们可以做出一个合理的猜测:有一些python程序只是临时完成一些琐碎的工作,比如统计某个特定文件中的词频信息,这样的程序可能仅仅运行一次,然后就再没用了,所以也就没有保存其对应的pyc文件的必要。因此,对于直接用pyhton demo.py这样形式执行的程序,python就不会存储编译结果了。不过可以用上边的命令手动编译。

但是加入说demo.py中实现的是一个需要被重用的类时。我们就希望能存储其对应的PyCodeObject对象,这样下次python就不会再次进行编译了。当在另一个程序,比如说在demo.py中对demo.py进行一个import demo的动态加载动作之后,你就会发现,python会为其产生pyc文件了。

这意味着python的import机制会触发pyc文件的生成。实际上,在python运行的过程中,如果碰到import abc 这样的语句,那么python将到设定好的path中寻找abc.pyc或者abc.dll文件,如果没有这些文件知识发现了abc.py,那么python会首先将abc.py编译成相应的PyCodeObject的中间结果,然后创建abc.pyc文件,并将中间结果写入该文件。接下来,python才会对abc.pyc文件进行import的动作,实际上就是将abc.pyc文件中的PyCodeObject重新在内存中复制出来。

在python中访问PyCodeObject对象

在python中,有与C 一级的PyCodeObject对象对应的对象————code对象。这个对象是对C 一级的PyCodeObject对象的一个简单包装,通过code对象,我们可以访问PyCodeObject对象中的各个域。
image

pyc文件的生成

内容太多了,看书吧。

字节码

python标准库提供了对python的code对象进行解析的工具dis。dis提供一个名为dis的方法,这个方法接受一个code对象,然后会输出code对象里的字节码指令信息。

image

  • 最左边一列显示的是字节码指令对应源码中的行数,
  • 左起第二列显示的是字节码指令再co_code中的偏移位置,
  • 第三列显示了当前的字节码指令,
  • 最后一列显示了当前字节码指令的参数。

原文地址:http://www.cnblogs.com/yimeimanong/p/16851443.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性