2 回答
TA贡献1815条经验 获得超13个赞
您的问题分为两个步骤(从我的角度来看):
浏览您的目录和子目录并找到您要导入的所有 .py 文件的名称
导入它们!
为了解决(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。
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)
添加回答
举报