将Python包合并成一个模块。
项目描述
一个基于包的源代码合并器,用于将Python包合并成一个模块。
amalgamate实用程序使得在几乎不增加运行时成本的情况下,加速Python包启动时间的可能性。如果这听起来好得令人难以置信,请继续阅读详细信息!
这里的重大想法是将包或子包中的大多数源文件粘合在一起形成一个单独的模块,称为__amalgam__.py。结合__init__.py中的某些钩子,这应该可以显著减少在包内部搜索的文件数量。这在导入时间成为主要启动时间成本的较大项目中至关重要。
脚本 amalgamate.py 自动为软件包创建 __amalgamate__.py 文件。这将创建并解决软件包中所有模块的依赖图。然后它会遍历每个模块,将其粘合到 __amalgamate__.py 中,并在过程中移除重复的导入。
此外,amalgamate.py 脚本将大多数非包导入自动设置为延迟加载。这使得开发者可以编写尽可能多的导入,而无需担心启动时间。非包模块实际上只有在使用时(即访问属性时)才会导入到 __amalgam__.py 中。
这会产生一些有趣的影响,例如:
所有合并的模块共享相同的全局变量(因此请注意命名事项),
调试时,大多数东西看起来都像是来自 __amalgam__ 的代码,除非在导入之前设置了环境变量。
并非所有导入都可以延迟加载。
导入
代码合并器的工作方式是,应从同一软件包(并合并)中的其他模块使用 from-import,而不使用 as-子句。例如,假设 z 是软件包 pkg 中的一个模块,它依赖于同一软件包中的 x 和 y。模块 z 应仅使用以下导入
from pkg.x import a, c, d from pkg.y import e, f, g
这些 from-imports 模拟了所有的 x、y 和 z 模块具有相同的 globals()。这是因为合并器将所有这样的模块放入同一个全局变量中,这就是 from-imports 所做的。例如,xonsh.ast 和 xonsh.execer 都在同一软件包 xonsh 中。因此,它们应使用上述 from from-import 语法。
或者,对于当前软件包之外(或未合并的)的模块,导入语句应该是 import pkg.x 或 import pkg.x as name。这是因为这是合并器能够自动安全地插入延迟导入的唯一情况。假设我们再次在 z 中,并依赖于 dep、collections.abc 和子软件包 pkg.sub 中的模块。以下都是可接受的
import dep import collections.abc as abc import pkg.dep.mod0 import pkg.dep.mod1 as mod1
这里重要的是在整个软件包 pkg 的所有模块中保持此类导入的一致性。
警告:您不应使用 from pkg.i import j 的形式导入合并包之外的模块。这是因为 from pkg.x import name 可能导入一个无法延迟构建的变量,或者可能导入一个模块。合并器被迫保留这些导入语句的原始形式,这意味着它们不能自动延迟或删除。因此,它们被迫在导入 __amalgam__.py 时导入。
所以,遵循的简单规则是
直接使用 from-import 从同一软件包中的模块导入对象,
通过直接导入或导入-as 语句从包外的模块导入对象。
__init__.py 钩子
为了使这一切正常工作,软件包的 __init__.py 需要一个预定义的空间,以便 amalgamate.py 可以将其钩子写入。在其最简单的形式中,这是由以下行定义的:
# amalgamate exclude # amalgamate end
脚本 amalgamate.py 将填充这两行之间的空隙,并在需要时覆盖它们。初始排除行接受空格分隔的模块名称列表,以排除合并
# amalgamate exclude foo bar baz # amalgamate end
您还可以提供任意多的排除行,尽管应该只有一个结束行
# amalgamate exclude foo # amalgamate exclude bar # amalgamate exclude baz # amalgamate end
请注意,所有名称以双下划线开头的模块,如 __init__.py 和 __main__.py 都会自动排除。
命令行界面
命令行界面是合并的包名称列表
$ amalgamate.py pkg pkg.sub0 pkg.sub1
您还可以提供 --debug=NAME 名称来声明导入调试的环境变量名称
$ amalgamate.py --debug=PKG_DEBUG pkg pkg.sub0 pkg.sub1
默认情况下,这个环境变量简单地叫做 DEBUG。如果这个环境变量存在并且设置为非空字符串,那么所有合并的导入都会被跳过,并且包中的模块将按正常方式导入。例如,假设您有一个导入您的包的脚本,并且您想看到模块名称,您可以运行脚本
$ env PKG_DEBUG=1 python script.py
来抑制合并导入。
设置钩子
我们建议在每次运行 setup.py 时都运行 amalgamate.py。这保持 __amalgam__.py 和 __init__.py 与包的其他部分同步。您可以在项目中自由使用以下钩子函数
def amalgamate_source(): """Amalgamates source files.""" try: import amalgamate except ImportError: print('Could not import amalgamate, skipping.', file=sys.stderr) return amalgamate.main(['amalgamate', '--debug=PKG_DEBUG', 'pkg'])
此外,您还可以将 amalgamate.py 脚本复制到您的项目中。它只是一个单独的文件!
黑暗魔法
这是通过语法树转换实现的,因此开发人员可以主要编写正常的 Python,而无需担心导入速度。这就是魔法的来源。
黑暗来自一个名为 JsonCpp 的项目。JsonCpp 有一个 合并脚本,将整个项目粘合为一个单独的头文件和一个单独的源文件。这是一个惊人的想法。关键是 JsonCpp 的合并是用 Python 编写的 :)
项目详情
amalgamate-0.1.3.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | e38696998145ee7b5eaabe7ab60e60108e64448eefcb73eb7f917fe24e6ff761 |
|
MD5 | 3e5fa4216bf593224baf08ef4ecbfadd |
|
BLAKE2b-256 | 612570108f11c9782da4e258cc3dd75f9b3fa6f645b202536bc73e90d33b8de1 |