如何从Python源代码中删除真正作为注释的字符串字面量?

-2 投票
1 回答
1187 浏览
提问于 2025-04-18 06:47

我需要快速写(或者借用)一些东西,任何语言都可以,自动过滤大量的Python源代码,以去掉注释。这样做的目的是让目标平台上的代码更紧凑(顺便说一下,也让逆向工程变得稍微困难一点)。我绝对不能修改代码的行为,偶尔留下几个注释也没关系。我的输入和输出应该是一个.py文本文件,假设它是有效的Python 2.x代码(假设:只限于ASCII,我会处理UTF8)。

严格来说,我需要去掉以下定义的注释:

注释以一个井号字符(#)开始,这个井号不是字符串字面量的一部分,并且在物理行的末尾结束。

因为Python的词法分析器已经为我处理了这个问题,最后代码会以.pyc的形式分发。真可惜,因为我清楚怎么干得很干净(唯一稍微复杂的部分是Python中字符串字面量的语法)。

我的问题是,粗略看一下我需要过滤的Python源代码,发现里面有很多注释并不是用#引入的,而是一些字符串字面量,它们没有任何实际用途。这些字符串字面量肯定会保留在.pyc的标记文件中。听说这些字符串字面量是为了方便自动生成文档和编辑而存在的。很多实际上是注释的字符串字面量嵌入在函数定义中,比如:

def OnForceStatusChoice(self,event):
    """Action when a status is selected"""
    self.ExecutionPanel.SetFocus()

另一方面,还有很多字符串字面量是有用的文本,包括要显示给用户的英文文本和表格的初始化。这让我们很难自动且安全地识别出哪些字符串字面量实际上是注释,哪些是有用的内容。

根据我的抽样,大多数实际上是注释的字符串字面量似乎是用"""引入的(例外不多,我或许可以接受),但我知道足够的Python,明白我不能安全地去掉所有这些字符串字面量。

我能否安全地(或者在某种合理的编码风格假设下)假设:

  1. 如果一个.py文件的第一行(忽略#注释)是一个字符串字面量,它可以被递归地去掉吗?如果可以,这个规则能否通过忽略(并保留)其他内容来变得更强大,而不仅仅是#注释?
  2. 任何在行最左边开始的字符串字面量都可以被去掉吗?
  3. 任何在语法上匹配函数定义(像上面的def)之后开始的字符串字面量都可以被去掉吗?如果可以,我该如何准确地定义语法上匹配函数定义

请回答得像我连Python和一堆随机字节都分不清,这离现实也不远。

1 个回答

6

你所说的注释其实是 文档字符串

在函数体内作为第一条语句出现的字符串,会变成这个函数的 __doc__ 属性,也就是函数的文档字符串。

根据 词汇表 的定义:

在类、函数或模块的第一条表达式中出现的字符串。虽然在执行时会被忽略,但编译器会识别它并把它放入包含类、函数或模块的 __doc__ 属性中。由于可以通过反射获取到它,所以这是记录对象文档的标准位置。

你可以通过使用 -OO 命令行选项来将项目编译成 .pyo 文件:

-O
开启基本优化。这会把编译后的(字节码)文件的扩展名从 .pyc 改为 .pyo。还可以查看 PYTHONOPTIMIZE

-OO
除了 -O 的优化外,还会丢弃文档字符串。

你可以使用 compileall 模块 作为命令行工具来编译项目中的所有文件:

python -OO -m compileall path/to/project/

不过,Python 的字节码是 非常简单 的,可以被反编译。去掉文档字符串并不会给你带来太多好处。

如果你需要更专业的处理,你得学习如何使用 ast 模块 来解析 Python 代码,生成解析树,修改这棵树(比如去掉所有文档字符串),然后再写出修改后的 Python 代码。可以参考 解析一个 .py 文件,读取 AST,修改它,然后写回修改后的源代码 来获取一些方向上的提示。

撰写回答