作为Python爱好者,需要了解.py脚本的基本运行机制及特性:

在很多工作上Python的运行流程基本上取决于用户,因此源码不需要编译成二进制代码(否则无法实现大部分贴近用户的特性),而直接从源码运行程序。当我们运行python文件程序的时候,Python解释器将源码转换为字节码,然后再由解释器来执行这些字节码。

因此总的来说,它具有以下三条特性

源码距离底层更远(根据官方文档的解释。不说,你们也感觉得到。)

运行时都需要生成字节码,交由虚拟机执行。(你们问我虚拟机在哪儿?!你们也不看看各自都是用什么软件执行的!没错,就是解释器,别和我说是IDLE啊。虚拟机具体实现了由switch-case语句构成的框架函数PyEval_EvalFrameEx,刚刚说的字节码就是这货执行的。)

每次执行脚本,虚拟机总要多出加载和链接的流程。(所以呢,相比于编译型语言就有点慢了。这与“有丝分裂间期”一样,准备东西也要花时间啊!)

那么,有人要问了:“不是说,运行时总要生成字节码么!那,字节码都去哪儿了?”

咳咳,别急!容我先说说,虚拟机它是怎么执行脚本的:

完成模块的加载和链接;

将源代码翻译为PyCodeObject对象(这货就是字节码),并将其写入内存当中(方便CPU读取,起到加速程序运行的作用);

从上述内存空间中读取指令并执行;

程序结束后,根据命令行调用情况(即运行程序的方式)决定是否将PyCodeObject写回硬盘当中(也就是直接复制到.pyc或.pyo文件中);

之后若再次执行该脚本,则先检查本地是否有上述字节码文件。有则执行,否则重复上述步骤。

你看!在我们点击(或输入命令)运行脚本,并悠闲地喝咖啡时,“人家”虚拟机做了这么多的事情。不过,你有没有发现.pyc或.pyo文件是否生成,是取决于我们如何运行程序的(虽然我们不知道要怎么做)。

同样,有人会吐槽:“哼!为什么不直接生成这些文件,这样来得不是‘更快、更高、更强’!”

其实,虚拟机也是讲究效率的。毕竟对于比较大的项目,要将PyCodeObject写回硬盘也是不可避免地要花些时间的,而且它又不知道你是不是也就只执行一次,之后就对刚刚跑完的脚本“弃之不顾”了呢。不过,它其实也有贴心的一面。

比如,若你在命令行直接输入“python path/to/projectDir”(假设projectDir目录含有“main.py”文件,以及其他将要调用的模块),那么程序运行结束后便自动为当前目录下所有的脚本生成字节码文件,并保存于本地新文件夹pycache当中。(这也有可能是IDE写小项目时自动生成.pyc文件的原因,不过问题描述略微暧昧。详情参见上面知乎问题板块)

或者是,在命令行输入“python path/to/projectDir/main.py”,则生成除main.py外脚本的字节码文件。

不过总的来说,上述这两种行为都大大缩短了项目运行前的准备时间(毕竟分工明确的程序,规模应该不会太小,复用率也不会太低。除非吃饱了撑着,搞出这么多事情)

模块在每次导入前总会检查其字节码文件的修改时间是否与自身的一致。若是则直接从该字节码文件读取内容,否则源模块重新导入,并在最后生成同名文件覆盖当前已有的字节码,从而完成内容的更新(详见import.py)。

这样,就避免了修改源代码后与本地字节码文件产生冲突(当然,设计者也不会这么傻。)。

若想优化生成字节码,应注意这两点:

.pyc文件是由.py文件经过编译后生成的字节码文件,其加载速度相对于之前的.py文件有所提高,而且还可以实现源码隐藏,以及一定程度上的反编译。比如,Python3.3编译生成的.pyc文件,Python3.4就别想着去运行啦!

.pyo文件也是优化(注意这两个字,便于后续的理解)编译后的程序(相比于.pyc文件更小),也可以提高加载速度。但对于嵌入式系统,它可将所需模块编译成.pyo文件以减少容量。

但总的来说,作用上是几乎与原来的.py脚本没有区别的,也就是“然并卵 ”(当然,并非毫无作用。比如,我个人觉得用处最大的地方就是防止别人偷看我的代码,毕竟.py源文件是直接以源码的形式呈现给大家的。

在所有的Python选项中:

-O,表示优化生成.pyo字节码(这里又有“优化”两个字,得注意啦!)

-OO,表示进一步移除-O选项生成的字节码文件中的文档字符串(这是在作用效果上解释的,而不是说从-O选项得到的文件去除)

-m,表示导入并运行指定的模块

对此,我们可以使用如下格式运行.py文件来生成.pyc文件(以下调用均假设/path/to目录含有.py脚本):

python -m py_compile /path/to/需要生成.pyc的脚本.py #若批量处理.py文件

#则替换为/path/to/{需要生成.pyc的脚本1,脚本2,...}.py

#或者/path/to/

其效果等效于如下代码:

import py_compile

py_compile.compile(r'/path/to/需要生成.pyc的脚本.py') #同样也可以是包含.py文件的目录路径

#此处尽可能使用raw字符串,从而避免转义的麻烦。比如,这里不加“r”的话,你就得对斜杠进行转义

py_compile是Python的自带模块,这里面就两个函数。其下的py_compile.compile(file[, cfile[, dfile[, doraise]]])可将.py文件编译生成.pyc文件(默认),对应的参数解释如下

file,表示需要生成.pyc或.pyo文件的源脚本名(字符串);

cfile,表示需要生成.pyc或.pyo文件的目标脚本名。呃...好像没有区别(>﹏<) ,也就是源脚本-----[巴拉拉赐予你力量!编译!]( * ̄▽ ̄)o ─═≡※:☆----->目标脚本。当然,它默认是以.pyc为扩展名的路径名的字符串(呼...好长)。此外,当且仅当所使用的解释器允许编译成.pyo文件,才能以“.pyo”结尾。这也就是我上面为什么会在函数功能解释上加上“(默认)”这两个字的原因。

dfile,表示编译出错时,将报错信息中的名字“file”替换为“dfile”。

doraise,设置是否忽略异常。若为True,则抛出PyCompileError异常;否则直接将错误信息写入sys.stderr(什么!不知道sys.stderr?!温馨提示:sys.stderr是Python自带的标准错误输出)

另外,生成.pyo文件的格式调用如下:

python -O -m py_compile /path/to/需要生成.pyo的脚本.py

那么,有人要问了:为什么不是像生成.pyc文件那样采用“python -O /path/to/需要生成.pyo的脚本.py”形式的调用?

“忘记”说明这一点了,很多博客以及书籍都像我上面那样解释“-O”选项的作用,但详细来解释的话是-O选项,将.pyc文件优化(注意我一直强调的“优化”二字,这里就用到啦!)为.pyo文件,而不是将.py文件优化编译为.pyo文件。(其直接的结果是优化编译后的文件略微小于.pyc文件,也就是“减肥”了。现在,大家知道.pyo文件为什么小的原因了吧!)

注意:

以上无论是生成.pyc还是.pyo文件,都将在当前脚本的目录下生成一个含有字节码的文件夹pycache。

可能还有人会问,.pyd文件又是什么鬼?

别在意,那只是Python的动态链接库。如果要深究,还得扯上C++的知识。

再啰嗦一句:生成字节码的方法多了去了,不止以上这几种。比如,你们不妨试试将上面命令行调用中的“py_compile”改成“compileall”,而代码行中的“py_compile.compile”改成“compileall.compile_file”或“compileall.compile_dir”,又或者直接使用带有编译功能的IDE生成字节码。

再再啰嗦一句:知道Python运行机制,并不是我们一般人所必须的(吃瓜群众:“滚!我刚好不容易看完了,你才说?!”)。但是,了解其加速程序运行以及优化代码的设计思想,对于我们在日后构造缓存系统、如何减少不必要的运行时间,以及同步更新工作内容等问题上起到很大的借鉴作用。

若想要了解更多的内容,可以去翻翻官方文档和其他博客:

我将优质的技术文章和经验总结都汇集在了我的公众号【Python圈子】里。

在学习Python的道路上肯定会遇见困难,别慌,我这里有一套学习资料,包含40+本电子书,600+个教学视频,涉及Python基础、爬虫、框架、数据分析、机器学习等,不怕你学不会!还有学习交流群,一起学习进步~

python运行pyc文件_Python什么情况下会生成pyc文件?相关推荐

  1. android 在什么情况下会主动gc_Python 什么情况下会生成 pyc 文件?

    作者:折木奉太郎(经授权转载)来源:https://www.zhihu.com/question/30296617/answer/112564303 作为 Python 爱好者,需要了解 .py 脚本 ...

  2. python中dom模块_Python中使用dom模块生成XML文件示例

    在Python中解析XML文件也有Dom和Sax两种方式,这里先介绍如何是使用Dom解析XML,这一篇文章是Dom生成XML文件,下一篇文章再继续介绍Dom解析XML文件. 在生成XML文件中,我们主 ...

  3. python打开指定文件-python打包压缩、读取指定目录下的指定类型文件

    下面通过代码给大家介绍python打包压缩指定目录下的指定类型文件,具体代码如下所示: import os import datetime import tarfile import fnmatch ...

  4. U盘文件不删除情况下转换格式:

    U盘文件不删除情况下转换格式: Windows自带的Convert也有这个功能,鼠标依次打开,开始菜单-选择运行-输入"CMD.EXE"-确定,在打开窗口内输入:"Con ...

  5. 使用Python批量删除windows下特定目录的N天前的旧文件实战:Windows下批量删除旧文件、清除缓存文件、解救C盘、拒绝C盘爆炸

    使用Python批量删除windows下特定目录的N天前的旧文件实战:Windows下批量删除旧文件.清除缓存文件.解救C盘.拒绝C盘爆炸 目录

  6. target存放的是编译后的.class文件地方 默认情况下不会讲非class文件放入进入 如果要使用非.class文件 需要通过增加配置方式自动加入文件...

    target存放的是编译后的.class文件地方 默认情况下不会讲非class文件放入进入 如果要使用非.class文件 需要通过增加配置方式自动加入文件 转载于:https://www.cnblog ...

  7. Oracle 无备份情况下的恢复--控制文件/数据文件

    13.3无备份恢复控制文件 没有备份恢复控制文件其实就是在nomount状态,create control创建一个新的控制文件. dba必须知道4个信息才能正确的创建:数据库名.在线日志路径及其大小. ...

  8. 用 python 脚本,把当前目录及子目录下的 wav 音频文件转换为 flac 格式

    用 python 脚本,把当前目录及子目录下的 wav 音频文件转换为 flac 格式 import os, subprocessfor d,sd,files in os.walk('.'):for ...

  9. Git管理 本地文件误删(提交和没提交情况下),恢复文件的方法

    注意:右键空白区域弹出的git的版本库浏览器窗口,为本地库.提交与否影响的是此处是否和资源管理器目录的一致. 1.Git管理 本地文件误删(没提交情况下),恢复文件的方法: 2.Git管理 本地文件误 ...

最新文章

  1. Thymeleaf 学习笔记 (2)
  2. 32位数据源中没有mysql_如何在.NET中连接到MySQL数据库
  3. 笔记-项目采购管理-采购管理过程(具体过程)
  4. dos 一行两条命令
  5. 看完源码记不住,是我记性太差了吗?
  6. LeetCode 59. 螺旋矩阵 II
  7. Smack 4.3.2 发布,XMPP(jabber) 的 Java 客户端类库
  8. exchange 2010 relay设定
  9. sqlserver执行更新语句时出现异常,t 附近有语法错误
  10. 鸟哥的 Linux 私房菜学习笔记
  11. Backbox Linux简介与配置内网IP
  12. 我从不劝退,我就是退。
  13. pythonpandas入门_pyhton pandas数据分析基础入门(一文看懂pandas)
  14. QCustomPlot 1.0.1学习(5)-Sinc函数绘制
  15. 网页版全景图服务器搭建,云服务器全景图
  16. 使用pygame前的小插曲
  17. Postman参数化
  18. 癸酉本石头记后二十八回
  19. LeetCode:401(Python)—— 二进制手表(简单)
  20. 进程管理中,挂起的具体含义

热门文章

  1. 台式电脑怎么录屏?分享3个实用方法,简单又好用
  2. $.each的循环遍历
  3. 大都会人寿宣布高层领导变更
  4. ES6常用数组去重,数组排序
  5. 枚举法解决百元买百鸡问题及性能优化
  6. [2016陕西省赛B] Rui and her functions
  7. c语言 长整型的输出
  8. 643-Dijkstra迪杰斯特拉算法
  9. java实现迪杰斯特拉(Dijkstra)算法求解最短路问题
  10. Chipscope使用简介