如何将编译后的Python文件存储到单独的文件夹中?

35

Python是否可以将.pyc文件保存到位于sys.path中的另一个文件夹中?

/code
    foo.py
    foo.pyc
    bar.py
    bar.pyc

收件人:

/code
   foo.py
   bar.py
/code_compiled
   foo.pyc
   bar.pyc

我希望这样做,因为我感觉这样会更有条理。谢谢你能给我的任何帮助。


你尝试过Python 3.2吗?它实现了PEP 3147:PYC存储库目录(http://www.python.org/dev/peps/pep-3147/)。 - Noctis Skytower
如果您不关心 .pyc 文件,您可以在脚本末尾使用 os.system('del *.pyc')(例如在 Windows 上)来删除它们。 - Charles
10个回答

23

更新:

在Python 3.8中,-X pycache_prefix=PATH 命令行选项可以将 .pyc 文件写入到与代码树相对应的给定目录下的并行树中。请参见$PYTHONPYCACHEPREFIX 环境变量来源:@RobertT' answer

缓存位置在 sys.pycache_prefix 中报告(None 表示默认位置在 __pycache__ [自 Python 3.2 起] 子目录中)。

要关闭编译Python字节码的缓存,可以设置 -B,然后Python不会尝试在导入源模块时写入 .pyc 文件。请参见$PYTHONDONTWRITEBYTECODE 环境变量来源:@Maleev's answer


旧 [Python 2] 答案:

PEP 304:控制生成字节码文件。它的状态是已撤销,相应的补丁已被拒绝。因此可能没有直接的方法来实现它。

如果您不需要源代码,那么您可以直接删除*.py文件。*.pyc文件可以直接使用或打包成egg文件。


你可以编辑你的回答,加入一些有关更新的深入见解。 - Prof. Falken
1
错误。请往下看。简短的回答是除了在Python 2.x中使用非常hacky的方法外,没有其他办法;在Python 3.2及更高版本中则非常简单。 - Charles Merriam

18
在2003年那个古老而黑暗的时代,PEP 304出现了,试图解决这个问题。然而它的修补程序不尽人意。环境变量平台依赖和版本错误使其支离破碎,在荒原上散落成渣。
经过多年的煎熬,在2009年的最后几天,一个新的挑战者崛起。Barry Warsaw召唤了PEP 3147,让它运用简单却高超的武器进行战斗。PEP 3147摧毁了混乱的PYC文件,使战争中的Unladen Swallow和CPython解释器都不再为各自的PYC文件而争斗,允许Python安心休息,偶尔会在深夜里运行一些已逝去的幽灵程序。PEP 3147被独裁者认为是有价值的,并在3.2版本的时代被授予官方角色。
截至3.2版本,Python将模块的PYC文件存储在模块目录下的__pycache__中。每个PYC文件包含解释器的名称和版本,例如__pycache__/foo.cpython-33.pyc。您可能还有一个由早期版本的Python编译的__pycache__/foo.cpython-32.pyc。正确的“魔法”会发生:如果与源代码不同步,则使用正确的文件并重新编译。在运行时,请查看模块的mymodule.__cached__以获取PYC文件名,并使用imp.get_tag()进行解析。更多信息请参见What's New section
简而言之,在Python 3.2及以上版本中可以直接使用,而在此之前的版本则需要使用较差的替代方法。

3
PEP 3147只是部分解决方案。__pycache__目录仍然会使源代码凌乱。对于我来说,PYC文件的主要问题是在执行svn switch等操作后留下未删除的目录。 - Suor
似乎是一个美学问题:缓存的.pyc仅用于确切时间戳匹配;可能是来自filecmp.filecmp(浅拷贝=True)。虽然不太美观,但不应使用额外的缓存。 - Charles Merriam
请告诉我,像3.2中的大多数内容一样,这也包含在2.7中了吗? - ArtOfWarfare
该死 - 刚刚在 PEP 3147 中运行了建议的测试,结果返回了“False”。测试内容为:import imp; hasattr(imp, 'get_tag') - ArtOfWarfare
2
随着新王国的崛起,旧王国的人渴望新土地的财宝。许多关于类装饰器、整数除法和打印函数的突袭都获得了胜利。直到农民开始带回车载的表土时,旧王国的人才决定迁徙。 - Charles Merriam
显示剩余5条评论

8

仅仅近十年之后,Python 3.8 终于提供了支持,可以通过设置环境变量 PYTHONPYCACHEPREFIX 或使用 -X pycache_prefix=PATH 参数将字节码存储在单独的并行文件系统树中(官方文档在这里)。


6

如果你愿意为此完全放弃字节码生成,那么有一个命令行标志:

python -B file_that_imports_others.py

可以放入IDE的构建/运行首选项中


3

我不同意。原因是错误的或者至少没有很好地表述;但是方向是正确的。有很多理由可以将源代码与编译对象分离。以下是其中一些(这些都是我在某个时候遇到的):

  • 嵌入式设备从ROM中读取,但能够在RAM上使用内存文件系统。
  • 多操作系统开发环境意味着共享(使用samba/nfs/其他方式)我的工作目录并在多个平台上构建。
  • 商业公司希望仅分发pyc以保护知识产权。
  • 使用相同的工作目录更容易运行多个Python版本的测试套件。
  • 更轻松地清理过渡文件(rm -rf $OBJECT_DIR而不是find . -name '*.pyc' -exec rm -f {} \;)。

所有这些问题都有解决方法,但它们大多数是解决方法而不是解决方案。在大多数情况下,适当的解决方案是让软件接受替代位置来存储和查找这些过渡文件。


3

我同意,将代码分发为egg文件是保持其组织性的好方法。还有什么比包含所有所需代码和元数据的单个文件更有组织呢?改变字节码编译器的工作方式只会导致混淆。

如果你真的不喜欢那些pyc文件的位置,另一个选择是从只读文件夹运行。由于python无法写入,因此永远不会生成pyc文件。你要承受的代价是每个python文件在加载时都必须重新编译,无论你是否已经对其进行了更改。这意味着你的启动时间将会更长。


2
自 Python 3.2 版本以来,已经实现了PEP 3147:这意味着所有的 .pyc 文件都会生成在一个__pycache__目录中(对于每个包含 Python 文件的目录,都会有一个__pycache__目录,并且它将保存用于源代码的每个 Python 版本的 .pyc 文件)。

1

对于Python 3.8或更高版本:

PYTHONPYCACHEPREFIX设置(也可作为-X pycache_prefix)配置隐式字节码缓存使用单独的文件系统树,而不是每个源目录中默认的__pycache__子目录。

缓存的位置在sys.pycache_prefix中报告(None表示在__pycache__子目录中的默认位置)。


1

-2

"我觉得这样更有组织性" 为什么?怎么做?你想要实现什么目标?

保存编译器的输出的重点是在模块导入时节省一点加载时间。为什么要让它变得更加复杂呢?如果您不喜欢 .pyc 文件,那么可以定期运行“删除所有 .pyc 文件”的脚本。

它们并不是必需品;它们是有帮助的。为什么要关闭这个帮助呢?

这不是 C、C++ 或 Java,结果对象是必不可少的。这只是 Python 偶尔使用的缓存。我们在 Subversion 中将它们标记为“忽略”,以便它们不会意外地被检入。


8
为什么? 显然是因为它们使ls输出或Windows资源管理器文件列表更加视觉混乱。这是一个主观但相当合理的关注点,不是吗? - Maleev
@Maleev: "视觉混乱"?资源管理器可以按文件类型排序,将.pyc文件放在其他位置。Linux ls可以与通配符一起使用(即,ls *.py)。尝试重新排列文件是浪费时间的行为,因为有两种简单的方法可以减少视觉混乱。 - S.Lott
1
移动 .pyc 文件的位置并不等同于关闭该功能。这样做也不会使 Python 解释器更加复杂。所提出的论点基于对缓存实际含义的误解(即旨在增强引用局部性的临时存储设施)。缓存本质上是有损且局部化的。在 Python 项目层次结构中散布 .pyc 文件会破坏缓存的目的。最多可以说这是一种以文件层次结构卫生为代价的优化。 - Samuel A. Falvo II
1
Guido不同意。请参阅PEP 3147上的讨论线程,其中解决了这个确切的问题-他说该功能最大的卖点是修复混乱。在这个邮件线程中很好地下降,您会发现Guido的评论“这是此PEP的主要卖点!”关于文件将变得更清晰/更好组织。 https://mail.python.org/pipermail/python-dev/2010-April/099414.html - ArtOfWarfare

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接