如何从包含有效python的字符串中提取“可执行”字符串?

时间:2021-03-09 22:45:18

标签: python

我想解析一个字符串,例如:

code_str = """
def foo(a, b):
    return a + b

foo(
    a=1,
    b=2
)
"""

获取“可执行”字符串列表(多行与否)

code_snippets = extract_executable_strings(code_str)
assert code_snippets = [
    "def foo(a, b):\n\treturn a + b\n",
    "foo(\n\ta=1\n\tb=2\n)\n"
]

这样我就可以一一执行片段,或者生成一个等效的 doctest 字符串,例如:

"""
>>> def foo(a, b):
...     return a + b
>>>
>>> foo(
...     a=1,
...     b=2
... )
"""

当然,正则表达式可以涵盖简单的情况,但要涵盖所有有效的python,似乎我应该利用python的解析器本身,而不是自己重写(一个糟糕的)解析器。

1 个答案:

答案 0 :(得分:0)

这是完成问题描述的确切工作的函数。

from ast import parse as ast_parse

try:
    # Try ast.unparse (3.9+)
    from ast import unparse as ast_unparse
except ImportError:
    try:
        from astunparse import unparse as ast_unparse
    except ModuleNotFoundError:
        raise ModuleNotFoundError(
            "Can't find a ast unparse function -- you'll need python 3.9+ or (pip/conda) install astunparse")


def extract_executable_strings(code_str: str):
    """Extract code blocks from code_str

    >>> code_str = '''
    ... def foo(a, b):
    ...     return a + b
    ...
    ... foo(
    ...     a=1,
    ...     b=2
    ... )
    ... '''
    >>> blocks = list(extract_executable_strings(code_str))
    >>> len(blocks)
    2
    >>> print(blocks[0])
    def foo(a, b):
        return (a + b)
    >>> print(blocks[1])
    foo(a=1, b=2)

    """
    for ast_obj in ast_parse(code_str).body:
        yield ast_unparse(ast_obj).strip()