如何从Python源代码中删除真正作为注释的字符串字面量?
我需要快速写(或者借用)一些东西,任何语言都可以,自动过滤大量的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,明白我不能安全地去掉所有这些字符串字面量。
我能否安全地(或者在某种合理的编码风格假设下)假设:
- 如果一个
.py
文件的第一行(忽略#
注释)是一个字符串字面量,它可以被递归地去掉吗?如果可以,这个规则能否通过忽略(并保留)其他内容来变得更强大,而不仅仅是#
注释? - 任何在行最左边开始的字符串字面量都可以被去掉吗?
- 任何在语法上匹配函数定义(像上面的
def
)之后开始的字符串字面量都可以被去掉吗?如果可以,我该如何准确地定义语法上匹配函数定义?
请回答得像我连Python和一堆随机字节都分不清,这离现实也不远。
1 个回答
你所说的注释其实是 文档字符串:
在函数体内作为第一条语句出现的字符串,会变成这个函数的
__doc__
属性,也就是函数的文档字符串。
根据 词汇表 的定义:
在类、函数或模块的第一条表达式中出现的字符串。虽然在执行时会被忽略,但编译器会识别它并把它放入包含类、函数或模块的
__doc__
属性中。由于可以通过反射获取到它,所以这是记录对象文档的标准位置。
你可以通过使用 -OO
命令行选项来将项目编译成 .pyo
文件:
-O
开启基本优化。这会把编译后的(字节码)文件的扩展名从.pyc
改为.pyo
。还可以查看PYTHONOPTIMIZE
。
-OO
除了-O
的优化外,还会丢弃文档字符串。
你可以使用 compileall
模块 作为命令行工具来编译项目中的所有文件:
python -OO -m compileall path/to/project/
不过,Python 的字节码是 非常简单 的,可以被反编译。去掉文档字符串并不会给你带来太多好处。
如果你需要更专业的处理,你得学习如何使用 ast
模块 来解析 Python 代码,生成解析树,修改这棵树(比如去掉所有文档字符串),然后再写出修改后的 Python 代码。可以参考 解析一个 .py 文件,读取 AST,修改它,然后写回修改后的源代码 来获取一些方向上的提示。