RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 570823
Accepted
AccumPlus
AccumPlus
Asked:2020-09-27 15:49:46 +0000 UTC2020-09-27 15:49:46 +0000 UTC 2020-09-27 15:49:46 +0000 UTC

功能存在时模块的动态连接

  • 772

有一个带有“.py”扩展名文件的目录。您需要浏览文件并仅包括那些具有特定名称函数的文件。

我只得到这个(main.py 文件):

from os import listdir
from os.path import isfile, join
import importlib

filepath = './'
for f in listdir(filepath):
    if isfile(join(filepath, f)) and f != 'main.py':
        moduleloader = importlib.find_loader(f.split('.')[0])
        if moduleloader is not None:
            # check if module has function

它到达了评论的地方,但如何检查是个问题。还有一个问题,如何进一步使用这个功能?

python
  • 3 3 个回答
  • 10 Views

3 个回答

  • Voted
  1. Sergey Gornostaev
    2020-09-27T16:09:09Z2020-09-27T16:09:09Z
    import importlib
    from os import listdir
    from os.path import isfile, join, splitext
    
    for f in listdir(filepath):
        if isfile(join(filepath, f)) and f != 'main.py':
            module_name, _ = splitext(f)
            m = importlib.import_module(module_name)
            if hasattr(m, 'function_name'):
                function_name = getattr(m, 'function_name')
                function_name()
    
    • 1
  2. vadim vaduxa
    2020-09-27T21:36:08Z2020-09-27T21:36:08Z
    import os, sys, itertools
    
    def get_modules(fn_names: [str], folder: str) -> dict:
        sys.path.append(folder)  # путь поиска модуля
        def get():
            for file in os.listdir(folder):  # файлы+каталоги из folder
                if os.path.isfile(os.path.join(folder, file)):  # только файлы
                    name, ext = os.path.splitext(file)
                    if ext == '.py':  # расширения ".py"
                        module = __import__(name)  # локальный импорт модуля
                        for fn in fn_names:  # если несколько названий функций
                            if hasattr(module, fn):  # функция с определённым названием
                                yield fn, module  # вернуть модуль функции
        modules = {}  # {функ1:[модуль1,..], функ2:[..],..}
        for f, m in get():
            try: modules[f].append(m)
            except KeyError: modules[f] = [m]
        return modules
    
    if __name__ == '__main__':
        folder = '_Tmpc9'
    
        def test_files_creator(dt: {int: [int]}):
            '''создать файлы модулей и записать функции'''
            md = 'module_{}.py'
            fn = '''def fn_{0}(arg): print("call %s( %s ) ~ %s" % (fn_{0}.__name__, arg, sys.modules[__name__]))'''
            if not os.path.isdir(folder): os.makedirs(folder)
            for m in dt:
                j = os.path.join(folder, md.format(m))
                print('import sys\n', file=open(j, 'w'))
                for f in dt[m]: print(fn.format(f), file=open(j, 'a'))
    
        test_files_creator({1: [1, 2], 2: [1, 2], 3: [2]})
    
        ms = get_modules(fn_names=['fn_1', 'fn_2'], folder=folder)
    
        print('\n'.join('{}:{}<{} module'.format(k, [m.__name__ for m in v], len(v))
                        for k, v in ms.items()))
        print()
    
        m = ms['fn_1'][0]
        print(m)
        getattr(m, 'fn_1')('one')
    
        # имя модуля и функции можно использовать как если бы был обычный import:
        # динамическое подключение модуля
        globals().update({m.__name__: m for m in set(itertools.chain(*ms.values()))})
        print(module_2)
        module_2.fn_1('two')
    
        # динамическое подключение функции
        m = ms['fn_2'][2]
        globals()['fn_2'] = getattr(m, 'fn_2')
        print(m)
        fn_2('three')
    

    出去:

    fn_1:['module_1', 'module_2']<2 module
    fn_2:['module_1', 'module_2', 'module_3']<3 module
    
    <module 'module_1' from '_Tmpc9\\module_1.py'>
    call fn_1( one ) ~ <module 'module_1' from '_Tmpc9\\module_1.py'>
    <module 'module_2' from '_Tmpc9\\module_2.py'>
    call fn_1( two ) ~ <module 'module_2' from '_Tmpc9\\module_2.py'>
    <module 'module_3' from '_Tmpc9\\module_3.py'>
    call fn_2( three ) ~ <module 'module_3' from '_Tmpc9\\module_3.py'>
    
    • 1
  3. Best Answer
    jfs
    2020-09-28T06:13:48Z2020-09-28T06:13:48Z

    要加载给定路径中的所有模块,您可以使用pkgutil.iter_modules(path). 基于 , 的变体的优势glob('*.py')在于支持其他模块格式(zip 存档,目录,如果需要)。例如,g从目录中的所有模块调用一个函数modules,不包括 Python 包和当前模块:

    #!/usr/bin/env python
    import inspect
    import pkgutil
    
    for module_finder, name, ispkg in pkgutil.iter_modules(path=['modules']):
        if ispkg or name == __name__:
            continue # skip packages or itself
        mod = module_finder.find_module(name).load_module(name)
        g = next((f for funcname, f in inspect.getmembers(mod, inspect.isfunction)
                  if funcname == 'g'), None) # find *g* function in the *mod* module
        if g is None:
            print('no g function in {} module'.format(name))
        else: # call it
            g()
    

    要在模块中搜索函数,请使用inspect.getmembers()谓词。相比之下的优点是只会找到函数,忽略其他对象,如字符串、类。请注意,一个类在 Python 中是可调用的——如果它是一个类,它可以工作,但会返回——如果你想要不同的结果,请使用不同的谓词而不是.inspect.isfunctionhasattr()CC()inspect.isfunction(C)Falseinspect.isfunction()

    如果路径是相对路径(例如modules),那么它(通常)是相对于当前工作目录的,该目录可能与执行.

    请注意,当您导入模块时,将执行模块级别的代码。它可以是任意代码。不要导入其内容不受您控制的模块。

    考虑使用预先存在的工具unittest来py.test运行测试(如果您的模块包含测试),或yapsy插件包,或setuptools从它们的配置中已知的“入口点”setup.py(如果您的要求接近这些库所代表的功能)— 无需一次一个要求地重新发明轮子。

    • 1

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何停止编写糟糕的代码?

    • 3 个回答
  • Marko Smith

    onCreateView 方法重构

    • 1 个回答
  • Marko Smith

    通用还是非通用

    • 2 个回答
  • Marko Smith

    如何访问 jQuery 中的列

    • 1 个回答
  • Marko Smith

    *.tga 文件的组重命名(3620 个)

    • 1 个回答
  • Marko Smith

    内存分配列表C#

    • 1 个回答
  • Marko Smith

    常规赛适度贪婪

    • 1 个回答
  • Marko Smith

    如何制作自己的自动完成/自动更正?

    • 1 个回答
  • Marko Smith

    选择斐波那契数列

    • 2 个回答
  • Marko Smith

    所有 API 版本中的通用权限代码

    • 2 个回答
  • Martin Hope
    jfs *(星号)和 ** 双星号在 Python 中是什么意思? 2020-11-23 05:07:40 +0000 UTC
  • Martin Hope
    hwak 哪个孩子调用了父母的静态方法?还是不可能完成的任务? 2020-11-18 16:30:55 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    Arch ArrayList 与 LinkedList 的区别? 2020-09-20 02:42:49 +0000 UTC
  • Martin Hope
    iluxa1810 哪个更正确使用:if () 或 try-catch? 2020-08-23 18:56:13 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5