假设我在一个公共目录下有一堆 Python 文件,但其中可能存在任意数量的子目录:
/first/foo.py
/first/bar.py
/first/fizz/buzz.py
/first/numbers/one.py
/first/numbers/two.py
Run Code Online (Sandbox Code Playgroud)
我有一些任意文件,我想导入所有这些文件。手动,我可以这样做:
import first.foo
import first.bar
import first.fizz.buzz
import first.numbers.one
import first.numbers.two
Run Code Online (Sandbox Code Playgroud)
但相反,我希望能够做类似的事情:
import_everything_under('first')
Run Code Online (Sandbox Code Playgroud)
我知道已经出现了类似的问题:Recursively import all .py files from allfolders
但给出的答案和所谓的重复并不能回答这个问题。
这个问题被标记为可能重复:如何加载文件夹中的所有模块?
再说一遍,这并不能回答这个问题。该问题的答案不是递归的 - 它只会从直接目录导入项目,并且不包含子目录中的脚本,这是我的用例所需要的。
您的问题分为两个步骤(从我的角度来看):
浏览目录和子目录并找到要导入的所有 .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
Run Code Online (Sandbox Code Playgroud)
现在您已经有了 .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
Run Code Online (Sandbox Code Playgroud)
现在我们只需要把它们放在一起,编写一个函数来调用您的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
Run Code Online (Sandbox Code Playgroud)
请注意,我们必须调用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)
Run Code Online (Sandbox Code Playgroud)
此时,您可以像以前一样访问导入的任何模块import first.whatever
。例如,如果first/numbers/one.py
包含x=1
,那么您可以通过说来访问它one.x
。
归档时间: |
|
查看次数: |
4926 次 |
最近记录: |