编写带有修饰函数和导入的模块

Write Module with decorated functions and imports

我在 python 文件中有此代码:

from dec import my_decorator
import asyncio

@my_decorator
async def simple_method(bar):  # , x, plc_name, var_name):
    print("Henlo from simple_method\npartent:{}".format(parent))
    return


@my_decorator
async def other_simple_meth(bar, value):
    print("Henlo from other_simple_meth:\t Val:{}".format(value))
    return


async def main():
    print("Start Module-Export")
    open('module_functions.py', 'a').close()
    # Write all decorated functions to modue_functions.py
    print("Functions in module_functions.py exported")
    while True:
        asyncio.sleep(2)
        print("z...z...Z...")

我的目标是将所有修饰函数(包括导入依赖项)写入第二个模块文件(此处为 "module_functions.py")。我的 'module_functions.py' 文件应该如下所示:

from dec import my_decorator
import asyncio

@my_decorator
async def simple_method(bar):  # , x, plc_name, var_name):
    print("Henlo from simple_method\npartent:{}".format(parent))
    return


@my_decorator
async def other_simple_meth(bar, value):
    print("Henlo from other_simple_meth:\t Val:{}".format(value))
    return

我知道如何获取函数的引用和名称,但不知道如何将函数代码(包括装饰器和所有依赖项)"copy/paste" 放入单独的文件中。这甚至可能吗?

编辑:我知道 pickle 和 dill 存在,但这可能无法实现目标。问题是,其他人可能不知道转储文件的顺序并将它们加载回去 may/will 会导致问题。同样,似乎无法再次编辑此类加载的功能。

我找到了一个(不理想,但还可以)解决我的问题的方法。

I) 查找函数、协同程序等并将其写入文件 (works):

就像@MisterMiyagi 怀疑的那样,检查模块是一个不错的选择。对于常见的东西,可以使用 inspect.getsource() 获取代码并将它们写入文件:

# List of wanted stuff    
func_list = [simple_method, meth_with_input, meth_with_input_and_output, func_myself] 

    with open('module_functions.py', 'a') as module_file:
        for func in func_list:
            try:
                module_file.write(inspect.getsource(func))
                module_file.write("\n")
            except:
                print("Error :( ")

II) 但是装饰的东西呢(似乎可以)?

I) 不适用于修饰的东西,它只是被忽略而不抛出异常。好像用的是from functools import wraps。 在许多示例中,@wraps 装饰器被添加到装饰器 class 中。这对我来说是不可能的,但有一个很好的解决方法:

@wraps(lambda: simple_method) #<---add wraps-decorator here
@my_decorator
async def simple_method(parent):  # , x, plc_name, var_name):
    print("Henlo from simple_method\npartent:{}".format(parent))
    return

包装可以放在原来的装饰 method/class/function 上面,它看起来就像我想要的那样。现在我们可以将 simple_method 添加到 I) 的 func_list 中。

III) 进口呢?

好吧,实际读取函数的依赖关系似乎相当 tricky/impossible。我的解决方法是将所有想要的导入放入 class (sigh)。这个class可以丢进I)的func_list写入文件。

编辑: 有一种更简洁的方法,经过一些修改后,它也可能适用于 I) 和 II)。魔法模块是ast.

我已经覆盖了以下内容:

class ImportVisitor(ast.NodeVisitor):

    def __init__(self, target):
        super().__init__()
        self.file_target = target

    "pick these special nodes via overwriting: visit_classname." \
    "classnames are listed in https://docs.python.org/3.6/library/ast.html#abstract-grammar"
    def visit_Import(self, node):
        "Overwrite func!"
        "Write all statements just with import like -  import ast into file_target"
        str = 'import '+', '.join(alias.name for alias in node.names)
        self.file_target.write(str+"\n")

    def visit_ImportFrom(self, node):
        "Overwrite func!"
        "Write all statements with from ... import (like - from os.path import basename) into file_tagrget"
        str = 'from '+ node.module+ ' import '+', '.join(alias.name for alias in node.names)
        self.file_target.write(str+"\n")

现在我可以解析我自己的脚本名称并在 module_file 中填充导入和来自...在访问此树中的所有节点时它将找到的导入:

    with open('module_functions.py', 'a') as module_file:
        with open(basename(__file__), "rb") as f:
            tree = ast.parse(f.read(), basename(__file__))
            visitor = ImportVisitor(module_file)
            visitor.visit(tree)
            module_file.write("\n\n")