Python的-O开关从其编译的代码中剥离断言。
Python的-OO开关会执行此操作,还会剥离文档字符串。
有什么方法可以制作Python条形文档字符串,但不是断言吗?
特别是可以通过命令行还是使用内置的编译功能来实现?
答案 0 :(得分:1)
有点黑,但是您可以为代码生成Abstract Syntax Trees(AST),删除看起来 像 docstring的所有内容,然后传递更改后的内容向compile
的资产。
给出此模块:
$ cat func.py
"""
This is module-level docstring.
"""
def f(x):
"""
This is a doc string
"""
# This is a comment
return 2 * x
首先,从模块源代码生成ast。
>>> import ast
>>> with open('func.py') as f:
... src = f.read()
...
>>> tree = ast.parse(src)
转储ast显示存在文档字符串(注释不包含在ast中)
>>> ast.dump(tree)
"Module(body=[Expr(value=Str(s='\\nThis is module-level docstring.\\n')), FunctionDef(name='f', args=arguments(args=[arg(arg='x', annotation=None)], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=[Expr(value=Str(s='\\n This is a doc string\\n ')), Return(value=BinOp(left=Num(n=2), op=Mult(), right=Name(id='x', ctx=Load())))], decorator_list=[], returns=None)])"
现在是hacky部分:定义一个访问者,它将访问ast中的每个节点,并删除文档字符串。幼稚的实现只能删除不属于分配的只是字符串的任何表达式。
>>> class Transformer(ast.NodeTransformer):
...
... def visit_Expr(self, node):
... if isinstance(node.value, ast.Str):
... return None
... return node
如果代码包含多行字符串(尽管我尚未对此进行测试),则可能会出现问题。
如果该节点是一个表达式节点并且其值是一个字符串节点(如果将字符串绑定到一个名称,则该节点将是一个分配节点),那么更安全的实现可能会从任何模块,函数或类定义中删除第一个节点,而不是表达式)。
class Transformer(ast.NodeTransformer):
def visit_Module(self, node):
self.generic_visit(node)
return self._visit_docstring_parent(node)
def visit_FunctionDef(self, node):
self.generic_visit(node)
return self._visit_docstring_parent(node)
def visit_ClassDef(self, node):
self.generic_visit(node)
return self._visit_docstring_parent(node)
def _visit_docstring_parent(self, node):
# Common docstring removal code.
# Assumes docstrings will always be first node in
# module/class/function body.
new_body = []
for i, child_node in enumerate(node.body):
if i == 0 and isinstance(child_node, ast.Expr) and isinstance(child_node.value, ast.Str):
pass
else:
new_body.append(child_node)
node.body = new_body
return node
>>> # Transformer performs an in-place transformation.
>>> Transformer().visit(tree)
请注意新ast中不再存在文档字符串:
>>> ast.dump(tree)
"Module(body=[FunctionDef(name='f', args=arguments(args=[arg(arg='x', annotation=None)], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=[Return(value=BinOp(left=Num(n=2), op=Mult(), right=Name(id='x', ctx=Load())))], decorator_list=[], returns=None)])"
新的ast可以编译为代码对象并执行:
>>> ast.fix_missing_locations(new_tree)
>>> code_obj = compile(new_tree, '<string>', mode='exec')
>>> exec(code_obj, globals(), locals())
>>> globals()['f']
<function f at 0x7face8bc2158>
>>> globals()['f'](5)
10