专业汉语词典知识平台,分享汉字词语知识、历史文学知识解答!

励北网
励北网

pyc文件是什么,python中pyc文件详解

来源:小易整编  作者:小易  发布时间:2023-02-25 06:55
摘要:pyc文件是什么,python中pyc文件详解pyc文件的触发上一篇文章我们介绍了字节码,当时提到,py文件在执行的时候会先被编译成PyCodeObject对象,并且该对象还会被保存到pyc文件中。但不幸的是,事实并不总是这样,有时当我们运...

pyc文件是什么,python中pyc文件详解

pyc 文件的触发

上一篇文章我们介绍了字节码,当时提到,py 文件在执行的时候会先被编译成 PyCodeObject 对象,并且该对象还会被保存到 pyc 文件中。

但不幸的是,事实并不总是这样,有时当我们运行一个简单的程序时,并没有产生 pyc 文件。因此我们猜测:有些 Python 程序只是临时完成一些琐碎的工作,这样的程序仅仅只会运行一次,然后就不会再使用了,因此也就没有保存至 pyc 文件的必要。

如果我们在代码中加上了一个 import abc 这样的语句,再执行你就会发现 Python 为 abc.py 生成了 pyc 文件,这就说明 import 会触发 pyc 的生成。

实际上,在运行过程中,如果碰到 import abc 这样的语句,那么 Python 会在设定好的 path 中寻找 abc.pyc 或者 abc.pyd 文件。如果没有这些文件,而是只发现了 abc.py,那么会先将 abc.py 编译成 PyCodeObject,然后写入到 pyc 文件中。

接下来,再对 abc.pyc 进行 import 动作。对的,并不是编译成 PyCodeObject 对象之后就直接使用。而是先写到 pyc 文件里,然后再将 pyc 文件里面的 PyCodeObject 对象重新在内存中复制出来。

当然啦,触发 pyc 文件生成不仅可以通过 import,还可以通过 py_compile 模块手动生成。比如当前有一个 tools.py:

a = 1
b = "你好啊"

如何将其编译成 pyc 呢?

import py_compile
py_compile.compile("tools.py")

查看当前目录的 __pycache__ 目录,会发现 pyc 已经生成了。

pyc文件是什么,python中pyc文件详解

然后 py文件名.cpython-版本号.pyc 为编译之后的 pyc 文件名。

pyc 文件的导入

如果有一个现成的 pyc 文件,我们要如何导入它呢?

from importlib.machinery import SourcelessFileLoader
tools = SourcelessFileLoader(
    "tools", "__pycache__/tools.cpython-38.pyc"
).load_module()
print(tools.a)  # 1
print(tools.b)  # 你好啊

以上我们就成功手动导入了 pyc 文件。

pyc 文件包含的内容

pyc 文件在创建的时候都会往里面写入哪些内容呢?

1. magic number

这是 Python 定义的一个整数值,不同版本的 Python 会定义不同的 magic number,这个值是为了保证 Python 能够加载正确的pyc。

比如 Python3.7 不会加载 3.6 版本的 pyc,因为 Python 在加载 pyc 文件的时候会首先检测该 pyc 的 magic number。如果和自身的 magic number 不一致,则拒绝加载。

2. pyc 文件的写入时间

这个很好理解,在加载 pyc 之前会先比较源代码的最后修改时间和 pyc 文件的写入时间。如果 pyc 文件的写入时间比源代码的修改时间要早,说明在生成 pyc 之后,源代码被修改了,那么会重新编译并写入 pyc,而反之则会直接加载已存在的 pyc。

3. py 文件的大小

py 文件的大小也会被记录在 pyc 文件中。

4. PyCodeObject 对象

编译之后的 PyCodeObject 对象,这个不用说了,肯定是要存储的,并且是序列化之后再存储。

因此 pyc 文件的结构如下:

pyc文件是什么,python中pyc文件详解

注意:以上是 Python 3.7+ 的 pyc 文件结构,如果版本低于 3.7,那么开头没有 4 个 \x00。我们实际验证一下:

import struct
from importlib.util import MAGIC_NUMBER
from datetime import datetime
with open("__pycache__/tools.cpython-38.pyc", "rb") as f:
    data = f.read()
# 0 ~ 4 字节是 MAGIC NUMBER
print(data[: 4])  # b'U\r\r\n'
print(MAGIC_NUMBER)  # b'U\r\r\n'
# 4 ~ 8 字节是 4 个 \x00
print(data[4: 8])  # b'\x00\x00\x00\x00'
# 8 ~ 12 字节是 pyc 的写入时间(小端存储),一个时间戳
ts = struct.unpack("<I", data[8: 12])[0]
print(ts)  # 1671001724
print(
    datetime.fromtimestamp(ts)
)  # 2022-12-14 20:32:23
# 12 ~ 16 字节是 py 文件的大小
print(
    struct.unpack("<I", data[12: 16])[0]
)  # 21

结果和我们分析的一样,因此对于任何一个 pyc 文件来说,前 16 字节是固定的(如果 Python 低于 3.7,那么前 12 个字节是固定的)。

16 个字节往后就是 PyCodeObject 对象,并且是序列化之后的,因为该对象显然无法直接存在文件中。

import marshal
with open("__pycache__/tools.cpython-38.pyc", "rb") as f:
    data = f.read()
# 通过 marshal.loads 可以反序列化
# marshal.dumps 则表示序列化
code = marshal.loads(data[16:])
# 此时就拿到了 py 文件编译之后的 PyCodeObject
print(code)
"""
<code object <module> at 0x..., file "tools.py", line 1>
"""
# 查看常量池
print(code.co_consts)  # (1, '你好啊', None)
# 符号表
print(code.co_names)  # ('a', 'b')

问题来了,既然我们可以根据 pyc 文件反推出 PyCodeObject,那么能否手动构建 PyCodeObject 然后生成 pyc 呢?来试一下。

a = 1
b = 2
c = 3

上述代码编译之后的结果,就是我们要构建的 PyCodeObject。


本文地址:百科问答频道 https://www.neebe.cn/wenda/903398.html,易企推百科一个免费的知识分享平台,本站部分文章来网络分享,本着互联网分享的精神,如有涉及到您的权益,请联系我们删除,谢谢!


百科问答
小编:小易整编
相关文章相关阅读
  • Python前端是什么意思?

    Python前端是什么意思?

    Python前端是指利用Python进行网页开发的过程,是采用Python语言构建网页的技术。Python具有优秀的数据分析和可视化性能,具有更多分析和可视化专业应用,因此它也被开发者们当作WEB开发领域的第一选择语言来使用。Python...

  • MicroPython是什么

    MicroPython是什么

    MicroPython是Python3编程语言的一个完整软件实现,用C语言编写,被优化于运行在微控制器之上。运行在微控制器硬件之上的完全的Python编译器和运行时系统。提供给用户一个交互式提示符来立即执行所支持的命令。Mi...

  • Python语言有哪些特点

    Python语言有哪些特点

    简单易学、面向对象、可移植性、解释性、高级语言、可扩展性、丰富的库、规范的代码、开放源码软件。Python是一种面向对象的、解释型的、通用的、开源的脚本编程语言,它之所以非常流行为主要有三点原因:Python简单易用,学习成本低,看起来...

  • Python是什么意思

    Python是什么意思

    Python是计算机程序设计语言,应用于Web和Internet开发、人工智能、教育、软件开发等领域。Python的设计风格简单明确、清晰优雅,采用的都是最成熟的优化技术,非常受用户欢迎。Python是计算机程序设计语言,应用...

  • Python的作用是什么

    Python的作用是什么

    Python是一种广泛使用的高级编程语言,属于通用型编程语言,是完全面向对象的语言。函数、模块、数字、字符串都是对象。经常被用于Web开发、GUI开发、操作系统、科学计算等应用范围。Python是一种广泛使用的高级编程语言,属于通用型编程...

  • Python可以应用在哪些领域

    Python可以应用在哪些领域

    常规软件开发、科学计、自动化运维、云计算、WEB开发、网络爬虫、数据分析、人工智能,Python可以在这些领域都可应用到。Python是一门解释型、面向对象、带有动态语义的高级程序设计语言。Python具有强大而丰富的类库,也经常被别人...

  • n的阶乘公式,Python实例计算数字n的阶乘

    n的阶乘公式,Python实例计算数字n的阶乘

    n的阶乘公式,Python实例计算数字n的阶乘前言此实例题目来自网络,很基础的练手项目,根据这个实例主要总结了四种方法,希望对你有帮助。本文章的目的是通过实例学习python,适合初学者观看,但是需要有一定的python基础。编程环境pyt...

  • ini是什么,Python中ini详解

    ini是什么,Python中ini详解

    ini是什么,Python中ini详解INI简介INI即Initialize初始化之意,早期是在Windows上配置文件的存储格式。INI文件的写法通俗易懂,往往比较简单,通常由节(Section)、键(key)和值(value)组成,se...

  • 周排行
  • 月排行
  • 年排行

精彩推荐