Неназначенный строковый литерал можно рассматривать как узлы в представлении абстрактного синтаксического дерева (AST) исходного кода. Тогда проблема сводится к тому, чтобы идентифицировать эти узлы и переписать AST без них, используя инструменты модуля ast .
Комментарии (# ...
) не анализируются в AST, поэтому для них не нужно кодировать.
Неназначенные строковые литералы являются узлами типа ast.Constant
и являются частью атрибута body
узлов, имеющих тела, такие как определения модулей, определения функций и класс определения. Мы можем идентифицировать эти узлы, удалить их из родительских body
и затем переписать AST.
import ast
import io
from unparse import Unparser
with open('comments.py') as f:
src = f.read()
root = ast.parse(src)
# print(ast.dump(root)) to see the ast structure.
def filter_constants(node):
if isinstance(node, ast.Expr):
if isinstance(node.value, ast.Constant):
if isinstance(node.value.value, str):
return None
return node
class CommentRemover(ast.NodeTransformer):
def visit(self, node):
if hasattr(node, 'body'):
node.body = [n for n in node.body if filter_constants(n)]
return super().visit(node)
remover = CommentRemover()
new = remover.visit(root)
ast.fix_missing_locations(new)
buf = io.StringIO()
Unparser(new, buf)
buf.seek(0)
print(buf.read())
Вызов сценария для этого кода (comments.py):
"""Module docstring."""
# A real comment
"""triple-double-quote comment"""
'''triple-single-quote comment'''
"'''weird comment'''"
"\"\"\"\n comment \"\"\""
NOT_A_COMMENT = 'spam'
42
def foo():
"""Function docstring."""
# Function comment
bar = 'baz'
return bar
class Quux:
"""class docstring."""
# class comment
def m(self):
"""method comment"""
return
Дает этот вывод:
NOT_A_COMMENT = 'spam'
42
def foo():
bar = 'baz'
return bar
class Quux():
def m(self):
return
Примечания:
- unparse скрипт находится в папке
Tools/parser
вашего дистрибутива Python (в v3.8 - в предыдущие версии были в Tools
или в папке Demo
). Его также можно загрузить с github - . Убедитесь, что вы загружаете версию для своей версии Python По состоянию на Python 3.8, класс ast.Constant
используется для всех константных узлов; для более ранних версий вам может понадобиться использовать ast.Num
, ast.Str
, ast.Bytes
, ast.NameConstant
и ast.Ellipsis
в зависимости от ситуации. Таким образом, в filter_constants это может выглядеть следующим образом:
def filter_constants(node):
if isinstance(node, ast.Expr):
if isinstance(node.value, ast.Str):
return None
return node
Начиная с Python 3.9 модуль ast предоставляет функцию unparse , которая может использоваться вместо unparse
скрипт
src = ast.unparse(new)
print(src)