专业IT网络知识平台,分享IT百科知识、生活百科知识解答!

易企推科技
易企推科技

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。


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


IT百科
小编:小易整编
相关文章相关阅读
  • Python基础

    Python基础

    前言python,是龟叔在1989年为了打发无聊的圣诞节而编写的一门编程语言,特点是优雅、明确、简单,现今拥有丰富的标准库和第三方库。python适合开发web网站和各种网络服务,系统工具和脚本,作为“胶水”语言把其他语言开发的模块包装起来...

  • python怎么实现三子棋游戏

    python怎么实现三子棋游戏

    一、基本流程三子棋游戏实现逻辑如下:1、创建初始化3*3棋盘;2、玩家执U子,先进行落子;3、胜负判定【胜、负、和棋】,若胜负未分,则继续如下4、电脑执T子,进行落子;5、胜负判定,若胜负未分,则从步骤2继续执行二、基本步骤1、菜单界面选择...

  • Python服务器编程:使用PyAudio进行音频处理

    Python服务器编程:使用PyAudio进行音频处理

    python是一种功能强大的编程语言,可以用于从简单的脚本到复杂的应用程序和服务器。pyaudio是python中一种流行的音频处理库,可以用于录制、播放和处理音频数据。在本文中,我们将探讨如何使用PyAudio来开发一个Python服务器...

  • 如何用Python中的jieba库?

    如何用Python中的jieba库?

    python中jieba库(中文分词库)使用安装教程介绍jieba是优秀的中文分词第三方库。由于中文文本之间每个汉字都是连续书写的,我们需要通过特定的手段来获得其中的每个单词,这种手段就叫分词。而jieba是python计算生态中非常优秀的...

  • python框架是什么,主流框架有哪些

    python框架是什么,主流框架有哪些

    Python框架通常分为全栈框架和非全栈框架。全栈框架设计从用户体验到数据库的所有技术,非全栈框架则并不包含整个开发的全部技术。下面是15个最受欢迎的Python开源框架。这些框架包括事件I/O,OLAP,Web开发,高性能网络通信,测试,...

  • python中divmod是什么

    python中divmod是什么

    python中pmod是什么?下面给大家带来pmod的相关介绍。pmod函数是Python的内置函数,它可以把除数和余数运算结果结合起来,返回一个包含商和余数的元组(a//b,a%b)。语法 pmod(pidend,pisor)...

  • Python中的GIL是什么

    Python中的GIL是什么

    为什么需要GILgil本质上是一把锁,学过操作系统的同学都知道锁的引入是为了避免并发访问造成数据的不一致。cpython中有很多定义在函数外面的全局变量,比如内存管理中的 usable_arenas 和 usedpools,如果多个线...

  • Python函数介绍:repr函数的用法和示例

    Python函数介绍:repr函数的用法和示例

    Python函数介绍:repr函数的用法和示例Python是一种广泛应用于各种领域的高级编程语言,它为开发者提供了众多强大的函数和方法。其中,repr函数是一个非常有用的函数之一,它可以用于返回一个对象的字符串表示。在Python中,rep...

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

精彩推荐