如果想要将Python代码中的函数实现全替换掉,但是保留函数定义,要怎么做?

当然,首先还是看下什么时候需要做这样的事情吧。一种情况就是,当Python代码不想对外开放,但又需要提供文档接口说明的时候。通过pydoc生成文档自然是一种选择,不过如果想配合PyCharm进行自动提示,那么还是有一份不含有具体实现的Python代码最为方便。

那如何实现呢?还是借助Python的ast模块。在之前使用ast移除代码中的print语句里面就曾借用ast模块来移除print语句,这里也是同样的处理思路。通过ast构建抽象语法树,找到Python函数定义节点,然后移除子节点,同时保留docstring。

代码很短,直接来看吧,

class CleanFunc(NodeTransformer):

    def visit_FunctionDef(self, node):
        # __init__特殊处理,成员字段基本都在__init__中进行定义,因此保留函数体
        if node.name == '__init__' or not node.body:
            return node
        # 找到docstring对应的节点,保留,移除其余子节点
        child = node.body[0]
        if type(child) == ast.Expr and type(child.value) == ast.Str:
            node.body = [child, ast.Expr(value=ast.Pass())]
        else:
            node.body = [ast.Expr(value=ast.Pass())]
        return node


def clean_func(input_path, output_path):
    with open(output_path, 'w') as outputs:
        outputs.write(astor.to_source(CleanFunc().visit(astor.parsefile(input_path))))
    outputs.flush()

比如用下面这段简单的定义去运行上述清理逻辑之后,可以得到后面的输出,

输入,

class Foobar(object):
        def __init__(self):
            self.name = None

        def get_name(self):
            """docstring"""
            return self.name

输出,

class Foobar(object):
        def __init__(self):
            self.name = None

        def get_name(self):
            """docstring"""
            pass