自动导入文件夹中的所有子模块,然后调用同名函数 - python 运行时检查相关

发布于 2024-10-18 03:26:29 字数 4056 浏览 0 评论 0原文

我的计算机上有一个打开的文件夹,

OpenFunctions\
    ____Template.py
    function1.py
    function2.py
    ......
    functionx.py

该文件夹是实验目的,用于扩展整个应用程序的功能。因此,我们认为这是一次快速而干燥的尝试,在这种情况下没有安全考虑。

我的目的是,如果我在 ____Template.py 之后放置一个 functionx.py,应用程序可以知道新函数可用,并将调用这个新加入的函数中定义的函数文件以某种方式 - 类似于插件系统,但应该有点不同。

所以我写了一个____inspect.py可以让应用程序有能力知道输入了什么。

这是

____inspect.py

def get_this_file_defined_functions(name_filter = "__"):
    import inspect, sys 
    f = inspect.getmembers(sys.modules[__name__], inspect.isfunction) 
    return [x for x in f if not x[0].startswith(name_filter)] 

def get_this_module_sub_modules(name_filter = "__"):
    import os.path, pkgutil
    pkgpath = os.path.dirname(__file__)
    m = [name for _, name, _ in pkgutil.iter_modules([pkgpath])] 
    return [x for x in m if not x[0].startswith(name_filter)]

def import_sub_modules_under_me(auto_exec_function = "auto_exec"):
    m = get_this_module_sub_modules()
    for i in m:  # need try except later
        exec "global %s; import %s" % (i, i)  
        #this will auto invoke __init__.py if sub modules folder is included
    for i in m:
        try:
            eval(i).eval(auto_exec_function)()
        except AttributeError:
            print "module %s has no function %s", % (i, auto_exec_function) 
        else:
            print "error on execute %s in module %s", % (auto_exec_function, i)

def execute_all_homonymy_functions(exec_function = "exec"):
    m = get_this_module_sub_modules()
    for i in m:
        #I need here for test if the module has been imported
        eval(i).eval(exec_function)()

基于

____Template.py

def __you_can_not_see_me(): pass  # because filtered by str.startswith()
def auto_exec(): pass             # this will be auto executed
def you_can_get_me(): pass
def you_can_get_me1(): pass
def you_can_get_me2(): pass

上述想法的,我还想将结构扩展到下面

main.py
____inspect.py
OpenFunctions\
    __init__.py
    ____Template.py
    function1.py
    function2.py
    ......
    functionx.py
    module_aa
        \__init__.py
          aa.py
          aa1.py

这是 main.py__init__.py 可能看起来像

import ____inspect
____inspect.import_sub_modules_under_me()
____inspect.execute_all_homonymy_functions("what_ever_i_want")

问题:

  1. 上面的__init__代码将不起作用,因为sys.modules[__name__]在调用时是____inspect但不是这 我想要的 OpenFunctions 或 module_aa ,有没有办法避免将 sys.modules[__name__] 传递给 import_sub_modules_under_me()< /code> 上的 main.py__init__.py

  2. 我想 execute_all_homonymy_functions() 将执行文件夹中的所有同名函数,无论它存在于子模块还是单个文件中,但我想调用所有最新版本如果是新添加的模块或运行时源已更改。然后我想使用代码 import aa, reload(aa) 但可能被认为是下面链接中的错误,有什么建议吗? 我在 __inspect.py

    中标记的问题我需要在这里测试模块是否已导入

    [http://stackoverflow.com/questions/5027352/how-to-test-if-one-python-module-has-been-imported]

  3. 我还想在调用文件中的一个函数之前知道它的返回类型,建议在每个函数上附加一个装饰。所以我的计划是:

\n

____decorate.py

def attrs(**kwds):
     def decorate(f):
         for k in kwds:
             setattr(f, k, kwds[k])
         return f
     return decorate

functionx.py
import ../____decorate.py

@attrs(argument_types=(int, int,),returns=int)
def __you_can_not_see_me(): pass

@attrs(argument_types=(int, int,),returns=int)
def auto_exec(): pass             # I will be auto executed

@attrs(argument_types=(int, int,),returns=int)
def you_can_get_me(): pass

@attrs(argument_types=(int, int,),returns=int)
def you_can_get_me1(): pass

@attrs(argument_types=(int, int,),returns=int)
def you_can_get_me2(): pass

检查案例是否可以正常工作?或者有更好的解决方案?

最后一句:下面的代码

exec "global %s; import %s" % (i, i) 
eval(i).eval(auto_exec_function)()

看起来很难看,上面两行有什么替代方案吗?

感谢您的帮助。

参考值, 肯尼迪

I have an open folder on my computer,

OpenFunctions\
    ____Template.py
    function1.py
    function2.py
    ......
    functionx.py

This folder is experimental purpose for extend the ability of the whole app can doing. So let’s just think it is a quick and dry trying, no security consideration in this case.

My purpose is, if I drop a functionx.py following the ____Template.py, the app can know the new functions is available and will invoke the functions defined in this new joined file in someway – something like the plugin system, but should be a bit different.

So I wrote a ____inspect.py may let application have an ability to know what has been inputed.

Here is the

____inspect.py

def get_this_file_defined_functions(name_filter = "__"):
    import inspect, sys 
    f = inspect.getmembers(sys.modules[__name__], inspect.isfunction) 
    return [x for x in f if not x[0].startswith(name_filter)] 

def get_this_module_sub_modules(name_filter = "__"):
    import os.path, pkgutil
    pkgpath = os.path.dirname(__file__)
    m = [name for _, name, _ in pkgutil.iter_modules([pkgpath])] 
    return [x for x in m if not x[0].startswith(name_filter)]

def import_sub_modules_under_me(auto_exec_function = "auto_exec"):
    m = get_this_module_sub_modules()
    for i in m:  # need try except later
        exec "global %s; import %s" % (i, i)  
        #this will auto invoke __init__.py if sub modules folder is included
    for i in m:
        try:
            eval(i).eval(auto_exec_function)()
        except AttributeError:
            print "module %s has no function %s", % (i, auto_exec_function) 
        else:
            print "error on execute %s in module %s", % (auto_exec_function, i)

def execute_all_homonymy_functions(exec_function = "exec"):
    m = get_this_module_sub_modules()
    for i in m:
        #I need here for test if the module has been imported
        eval(i).eval(exec_function)()

Here is the

____Template.py

def __you_can_not_see_me(): pass  # because filtered by str.startswith()
def auto_exec(): pass             # this will be auto executed
def you_can_get_me(): pass
def you_can_get_me1(): pass
def you_can_get_me2(): pass

based on above idea I also want to extend structure to below

main.py
____inspect.py
OpenFunctions\
    __init__.py
    ____Template.py
    function1.py
    function2.py
    ......
    functionx.py
    module_aa
        \__init__.py
          aa.py
          aa1.py

Here is the main.py while the __init__.py may looks like

import ____inspect
____inspect.import_sub_modules_under_me()
____inspect.execute_all_homonymy_functions("what_ever_i_want")

Questions:

  1. Above __init__ code will not working, because the sys.modules[__name__] is ____inspect when invoking but not the
    OpenFunctions or module_aa I want, is there a way to avoid pass the sys.modules[__name__] to the import_sub_modules_under_me() on the main.py or the __init__.py?

  2. I suppose execute_all_homonymy_functions() will execute all the same name function in folder no matter it is exists in a sub module or in a single file, but I want to invoke all and the latest version in case the module new added or the source has been changed runtime. Then I want to use the code import aa, reload(aa) but may be thought as the wrong on below link, any suggestions?
    The issue I marked I need here for test if the module has been imported in __inspect.py

    [http://stackoverflow.com/questions/5027352/how-to-test-if-one-python-module-has-been-imported]

  3. I also want to know the return type of one function in a file before invoking it, it was suggested to attach a decorate on each function. So my plan is:

\n

____decorate.py

def attrs(**kwds):
     def decorate(f):
         for k in kwds:
             setattr(f, k, kwds[k])
         return f
     return decorate

functionx.py
import ../____decorate.py

@attrs(argument_types=(int, int,),returns=int)
def __you_can_not_see_me(): pass

@attrs(argument_types=(int, int,),returns=int)
def auto_exec(): pass             # I will be auto executed

@attrs(argument_types=(int, int,),returns=int)
def you_can_get_me(): pass

@attrs(argument_types=(int, int,),returns=int)
def you_can_get_me1(): pass

@attrs(argument_types=(int, int,),returns=int)
def you_can_get_me2(): pass

Is it works ok for inspect case? Or there’s an better solution?

The last one: below code

exec "global %s; import %s" % (i, i) 
eval(i).eval(auto_exec_function)()

looks ugly, any alternative for above two lines?

Thanks for your help.

Rgs,
KC

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

柒七 2024-10-25 03:26:29

首先解决你的最后一个问题:要在最新版本的 Python 中动态导入模块,请使用 importlib.import_module() ,这就是它的用途。如果您使用的是较旧版本的 Python,则应该使用 __import__ (但请检查文档中该直接方法的特性 - 这是 import_module() 的原因)添加功能作为替代)。

要解决您的第一个问题:没有正式的可移植方法来检索有关调用函数的全局环境的信息,因此最正确的答案是简单地将 __name__ 作为参数传递到需要的地方。

在 Python 中重新加载总是有点危险,因为在重新加载时并非所有内容都可以正常工作(如果重新加载它们或它们引用的模块,即使许多标准库模块也会失败)。

我真的建议花一些时间探索有关 Python 插件架构的现有问题的答案:用 Python 构建最小的插件架构

To address your last question first: to dynamically import modules in recent versions of Python, use importlib.import_module(), that's what it is for. If you're on an older version of Python, you should use __import__ instead (but check the idiosyncracies of that direct approach in the docs - there's a reason the import_module() function was added as a replacement).

To address your first question: there is no officially portable way to retrieve information about the calling function's global environment, so the most correct answer is to simply pass __name__ in as an argument wherever it is needed.

Reloading in Python is always a little dangerous, since not everything works correctly under reloading (even many standard library modules will fail if you reload either them, or a module they reference).

I really suggest spending some time exploring the answers to this existing question about plugin architectures in Python: Building a minimal plugin architecture in Python

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文