为了账号安全,请及时绑定邮箱和手机立即绑定

如何从给定目录和所有子目录中动态导入所有 *.py 文件?

如何从给定目录和所有子目录中动态导入所有 *.py 文件?

暮色呼如 2022-05-24 09:36:00
假设我在一个公共目录下有一堆 Python 文件,但其中可能存在任意数量的子目录:/first/foo.py/first/bar.py/first/fizz/buzz.py/first/numbers/one.py/first/numbers/two.py我有一些任意文件要导入所有这些文件。手动,我可以这样做:import first.fooimport first.barimport first.fizz.buzzimport first.numbers.oneimport first.numbers.two但相反,我希望能够执行以下操作:import_everything_under('first')我知道已经弹出了一个类似的问题:Recursively import all .py files from all folder但是给定的答案和所谓的重复并不能回答这个问题。这个问题被标记为可能重复:如何加载文件夹中的所有模块?同样,这并不能回答这个问题。该问题的答案不是递归的——它只会从直接目录中导入项目,并且不包括我的用例需要的子目录中的脚本。
查看完整描述

2 回答

?
萧十郎

TA贡献1815条经验 获得超13个赞

您的问题分为两个步骤(从我的角度来看):

  1. 浏览您的目录和子目录并找到您要导入的所有 .py 文件的名称

  2. 导入它们!

为了解决(1),我们可以使用os.walk方法找到所有的 .py 文件。这个函数看起来像这样:

import os

def get_py_files(src):

    cwd = os.getcwd() # Current Working directory

    py_files = [] 

    for root, dirs, files in os.walk(src):

        for file in files:

            if file.endswith(".py"):

                py_files.append(os.path.join(cwd, root, file))

    return py_files

现在您已经有了 .py 文件的列表,我们需要一个可以动态导入它们的函数。


import importlib

def dynamic_import(module_name, py_path):

    module_spec = importlib.util.spec_from_file_location(module_name, py_path)

    module = importlib.util.module_from_spec(module_spec)

    module_spec.loader.exec_module(module)

    return module

现在我们只需要将它们放在一起,编写一个调用你的get_py_files函数然后循环结果的函数,用dynamic_import.


我假设您希望您在 python 脚本中使用的模块名称与文件名相同,但是您可以通过修改module_name下面函数中的变量来更改它。


def dynamic_import_from_src(src, star_import = False):

    my_py_files = get_py_files(src)

    for py_file in my_py_files:

        module_name = os.path.split(py_file)[-1].strip(".py")

        imported_module = dynamic_import(module_name, py_file)

        if star_import:

            for obj in dir(imported_module):

                globals()[obj] = imported_module.__dict__[obj]

        else:

            globals()[module_name] = imported_module

    return

请注意,我们必须调用globals()将模块添加到全局命名空间。如果不这样做,模块将被导入,但您将无法访问其中的任何内容。如果您希望它是星形导入,则可以传递star_import = True给。dynamic_import_from_src(如. 请注意,这可能会覆盖命名空间中的变量,但这是使用导入from first.foo import *的缺点之一。*


将它们全部放在一个块中,这样更容易一次看到它们:


import os

import importlib



def get_py_files(src):

    cwd = os.getcwd() # Current Working directory

    py_files = [] 

    for root, dirs, files in os.walk(src):

        for file in files:

            if file.endswith(".py"):

                py_files.append(os.path.join(cwd, root, file))

    return py_files



def dynamic_import(module_name, py_path):

    module_spec = importlib.util.spec_from_file_location(module_name, py_path)

    module = importlib.util.module_from_spec(module_spec)

    module_spec.loader.exec_module(module)

    return module



def dynamic_import_from_src(src, star_import = False):

    my_py_files = get_py_files(src)

    for py_file in my_py_files:

        module_name = os.path.split(py_file)[-1].strip(".py")

        imported_module = dynamic_import(module_name, py_file)

        if star_import:

            for obj in dir(imported_module):

                globals()[obj] = imported_module.__dict__[obj]

        else:

            globals()[module_name] = imported_module

    return


if __name__ == "__main__":

    dynamic_import_from_src("first", star_import = False)

此时,您可以访问您导入的任何模块,就像您使用import first.whatever. 例如,如果first/numbers/one.py包含x=1,那么您可以通过说 来访问它one.x。


查看完整回答
反对 回复 2022-05-24
?
胡子哥哥

TA贡献1825条经验 获得超6个赞

我自己一直在修补这个问题,我想我已经找到了另一种方法。我相信我自己的解决方案或@SyntaxVoid 的解决方案都应该有效。


from importlib import util

from os import path

from glob import glob



def import_submodules(start_path, include_start_directory=True):

    start_path = path.abspath(start_path)

    pattern = '**/*.py' if include_start_directory else '*/**/*.py'

    py_files = [f for f in glob(path.join(start_path, pattern), recursive=True) if not f.endswith('__.py')]


    for py_file in py_files:

        spec = util.spec_from_file_location('', py_file)

        module = util.module_from_spec(spec)

        spec.loader.exec_module(module)


查看完整回答
反对 回复 2022-05-24
  • 2 回答
  • 0 关注
  • 94 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信