以编程方式删除Python源中的类型提示

kla*_*ann 12 type-hinting python-3.x

我有一些为Python 3.5编写的源代码,我想在Python 3.4下创建可执行文件.我使用的3.5中唯一没有在3.4中提供的功能是类型提示,所以我想编写一个脚本来完全删除它们.

这看起来很容易乍一看我决定写一些正则表达式来做这个,但后来我考虑了一些边缘情况,我不知道如何解决这个更复杂的函数的问题:

def foo(bar: Dict[T, List[T]],
        baz: Callable[[T], int] = lambda x: (x+3)/7,
        **kwargs) -> List[T]:
Run Code Online (Sandbox Code Playgroud)

基本上,我必须解析整个事情并重建参数列表而不使用类型注释.我怎么会接近这个?

kla*_*ann 14

好的,我明白了:D

使用Python的内置AST模块来解析的源代码,然后将优秀astunparse库再次生成从解析AST的源代码.然后剩下的就是删除类型注释:

import ast
import astunparse

source="""
import typing
from typing import Dict, T, Callable
from typing import List

def foo(bar: Dict[T, List[T]],
        baz: Callable[[T], int] = lambda x: (x+3)/7,
        **kwargs) -> List[T]:
    pass
"""

class TypeHintRemover(ast.NodeTransformer):

    def visit_FunctionDef(self, node):
        # remove the return type defintion
        node.returns = None
        # remove all argument annotations
        if node.args.args:
            for arg in node.args.args:
                arg.annotation = None
        return node

    def visit_Import(self, node):
        node.names = [n for n in node.names if n.name != 'typing']
        return node if node.names else None

    def visit_ImportFrom(self, node):
        return node if node.module != 'typing' else None

# parse the source code into an AST
parsed_source = ast.parse(source)
# remove all type annotations, function return type definitions
# and import statements from 'typing'
transformed = TypeHintRemover().visit(parsed_source)
# convert the AST back to source code
print(astunparse.unparse(transformed))
Run Code Online (Sandbox Code Playgroud)

TypeHintRemover访问AST中的所有节点,并删除函数参数中的所有类型提示,每个函数的返回类型定义以及引用"键入"模块的所有import语句.

结果是:

def foo(bar, baz=(lambda x: ((x + 3) / 7)), **kwargs):
    pass
Run Code Online (Sandbox Code Playgroud)

  • 什么都没有。我将羞愧地垂头丧气,删除此讨论线程。终于睡个好觉之后,我现在意识到自己根本无法阅读。 (3认同)

Ily*_*yan 6

还有局部变量的类型提示(来自 Python 3.6)。我也修改了 @klamann 的代码以删除它们。另外,我使用 astor ( https://pypi.org/project/astor/ ) 来生成代码。

import ast
import astor
import sys


class TypeHintRemover(ast.NodeTransformer):

    def visit_FunctionDef(self, node):
        # remove the return type definition
        node.returns = None
        # remove all argument annotations
        if node.args.args:
            for arg in node.args.args:
                arg.annotation = None
        self.generic_visit(node)
        return node

    def visit_AnnAssign(self, node):
        if node.value is None:
            return None
        return ast.Assign([node.target], node.value)

    def visit_Import(self, node):
        node.names = [n for n in node.names if n.name != 'typing']
        return node if node.names else None

    def visit_ImportFrom(self, node):
        return node if node.module != 'typing' else None

def remove_type_hints(source: str):
    # parse the source code into an AST
    parsed_source = ast.parse(source)
    # remove all type annotations, function return type definitions
    # and import statements from 'typing'
    transformed = TypeHintRemover().visit(parsed_source)
    # convert the AST back to source code
    return astor.to_source(transformed)


def main():
    _, source_name, dest_name = sys.argv
    with open(source_name, "r") as sourceFile:
        source = "\n".join(sourceFile.readlines())
        dest = remove_type_hints(source)
        with open(dest_name, "w") as destFile:
            destFile.write(dest)

if __name__ == "__main__":
    main()
Run Code Online (Sandbox Code Playgroud)