如何用正则检测并清理仅含签名与注释的Python空函数?
问题描述
我有一个可能存在语法错误的Python代码文件,其中部分函数仅保留了签名,其余内容均为注释(包括单行#注释和多行docstring)。我希望通过正则表达式检测并清理这类空函数,同时也希望了解将多行注释转换为单行注释的方法,这是代码重构自动化工具的一部分。
输入代码示例
def this_function_has_stuff(f, g, K): """ Thisfunction has stuff in it """ if f: s = 0 else: u =0 return None def fuly_commented_fucntion(f, g, K): """ remove this empty function. Examples ======== >>> which function is >>> empty """ def empty_annotated_fn(name: str, result: List[100]) -> List[100]: """ Make some bla. Examples ======== >>> bla bla >>> bla bla x**2 + 1 """ def note_this_has_one_valid_line(f, K): """ Make some bla. Examples ======== >>> bla bla >>> bla bla x**2 + 1 """ return [K.abs(coff) for coff in f] def empty_with_both_types_of_comment(f, K): """ my bla bla Examples ======== 3 """ # if not f: # else: # return max(dup_abs(f, K)) SOME_VAR = 6
期望输出代码示例
def this_function_has_stuff(f, g, K): """ Thisfunction has stuff in it """ if f: s = 0 else: u =0 return None def note_this_has_one_valid_line(f, K): """ Make some bla. Examples ======== >>> bla bla >>> bla bla x**2 + 1 """ return [K.abs(coff) for coff in f] SOME_VAR = 6
解决方案
一、清理仅含注释的空函数
要匹配并删除这类空函数,需覆盖仅含多行docstring、仅含单行注释、两者混合三种场景,可结合多行模式使用以下正则方案:
实现代码
import re # 匹配空函数的正则表达式 pattern = r''' def\s+\w+\s*\([^)]*\)\s*(->\s*.+?)?:\s* # 匹配函数签名,支持类型注解和返回值注解 (?: """[\s\S]*?"""\s* # 匹配多行docstring | \#.*?\n\s* # 匹配单行注释 )* (?=\ndef|\n[^ \t]|$) # 断言后续是新函数、非缩进代码或文件结尾 ''' # 读取原代码 with open('your_code.py', 'r', encoding='utf-8') as f: code_content = f.read() # 替换空函数 cleaned_code = re.sub(pattern, '', code_content, flags=re.VERBOSE | re.MULTILINE | re.DOTALL) # 保存清理后的代码 with open('cleaned_code.py', 'w', encoding='utf-8') as f: f.write(cleaned_code)
规则说明
- 函数签名匹配:覆盖普通函数、带参数注解和返回值注解的函数定义。
- 注释匹配:用非贪婪模式匹配多行docstring和单行注释,避免跨函数误匹配。
- 边界断言:确保只删除独立的空函数,不会误删后续有效代码。
二、将多行注释转换为单行注释
1. 多行docstring转单行
docstring_pattern = r'"""(.*?)"""' def docstring_to_single_line(match): # 去除换行和多余空格,合并为单行 content = match.group(1).strip().replace('\n', ' ').replace(' ', ' ') return f'"""{content}"""' # 转换后的代码 single_line_doc_code = re.sub(docstring_pattern, docstring_to_single_line, code_content, flags=re.DOTALL)
2. 连续单行注释转单行
line_comment_pattern = r'(^\s*#.*?\n)+' def line_comments_to_single(match): # 提取每行注释内容,合并为一行 comment_lines = [line.strip()[1:].strip() for line in match.group(0).split('\n') if line.strip()] merged_content = ' '.join(comment_lines) return f'# {merged_content}\n' # 最终转换后的代码 final_single_line_code = re.sub(line_comment_pattern, line_comments_to_single, single_line_doc_code, flags=re.MULTILINE)
规则说明
- 多行docstring处理:将内部换行和缩进替换为空格,保持内容连贯。
- 连续单行注释处理:将多行独立的
#注释合并为一行,用空格分隔原内容。
注意事项
- 正则处理代码有局限性,无法完美处理嵌套注释、语法错误导致的异常格式等场景,建议结合
ast模块做语法分析辅助判断。 - 批量处理前务必备份原文件,避免误删有效代码。
- 若代码中存在复杂的注释嵌套或特殊格式,需根据实际情况调整正则表达式。
内容的提问来源于stack exchange,提问作者ishandutta2007
相关产品推荐
相关产品推荐

