繁体   English   中英

从多个目录导入python模块

[英]Importing python modules from multiple directories

我有一个python 2.6 Django应用程序,它的文件夹结构如下:

/foo/bar/__init__.py

我在文件系统上还有另外几个目录,其中充满了python模块,如下所示:

/modules/__init__.py
/modules/module1/__init__.py
/other_modules/module2/__init__.py
/other_modules/module2/file.py

每个模块__init__都有一个类。 例如分别为module1Class()module2Class() module2file.py包含一个名为myFileClass()的类。

我想做的是在/foo/bar/__init__.py放入一些代码,这样我就可以像这样导入Django项目:

from foo.bar.module1 import module1Class
from foo.bar.module2 import module2Class
from foo.bar.module2.file import myFileClass

具有模块的目录列表包含在Django配置的元组中,如下所示:

module_list = ("/modules", "/other_modules",)

我试过使用__import__vars()动态生成这样的变量:

import os
import sys 

for m in module_list:
    sys.path.insert(0, m)
    for d in os.listdir(m):
        if os.path.isdir(d):
            vars()[d] = getattr(__import__(m.split("/")[-1], fromlist=[d], d)

但这似乎不起作用。 有什么办法吗?

谢谢!

我可以看到您的代码中至少有一个问题。 线...

if os.path.isdir(d):

...不起作用,因为os.listdir()返回相对路径名,所以您需要将它们转换为绝对路径名,否则os.path.isdir()将返回False因为该路径不存在(相对于当前工作目录),而不是引发异常(IMO会更有意义)。

以下代码对我有用...

import sys
import os

# Directories to search for packages
root_path_list = ("/modules", "/other_modules",)

# Make a backup of sys.path
old_sys_path = sys.path[:]

# Add all paths to sys.path first, in case one package imports from another
for root_path in root_path_list:
    sys.path.insert(0, root_path)

# Add new packages to current scope
for root_path in root_path_list:
    filenames = os.listdir(root_path)
    for filename in filenames:
        full_path = os.path.join(root_path, filename)
        if os.path.isdir(full_path):
            locals()[filename] = __import__(filename)

# Restore sys.path
sys.path[:] = old_sys_path

# Clean up locals
del sys, os, root_path_list, old_sys_path, root_path, filenames, filename, full_path

更新

考虑一下,如果子目录中不包含此类文件,则检查__init__.py的存在可能比使用os.path.isdir()更安全,否则__import__()将会失败。

所以你可以改变线...

        full_path = os.path.join(root_path, filename)
        if os.path.isdir(full_path):
            locals()[filename] = __import__(filename)

...至...

        full_path = os.path.join(root_path, filename, '__init__.py')
        if os.path.exists(full_path):
            locals()[filename] = __import__(filename)

...但是可能没有必要。

我们全力以赴,改变了工作方式。 现在,用于查找模块的目录列表在Django配置中传递,并且每个目录都添加到sys.path中(类似于Aya提到的注释以及我之前做过但不太满意的操作)。 然后,针对其中的每个模块,检查__init__.py ,如果存在,则尝试将其视为要在应用程序内部使用的模块,而不使用foo.bar

这需要对我们与模块的交互方式以及开发人员对模块的编码方式进行一些调整(现在他们需要在模块中使用相对导入,而不是之前使用的完整路径导入),但是我认为这对于开发人员而言将是一个更容易的设计长期使用。

我们没有将它们添加到INSTALLED_APPS中,因为我们进行了一些异常处理,如果由于依赖关系问题或错误的代码而无法导入模块,则我们的软件将在没有该模块的情况下继续运行。 如果它们在INSTALLED_APPS中,则我们将无法在何时/如何处理这些异常上利用这种灵活性。

感谢您的所有帮助!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM