如何加载 Python 中子目录下的所有模块?

How do I load all modules under a subdirectory in Python?

我将经常使用的模块放在子目录 lib/ 中,并希望通过以下方式将所有模块加载到 main.py:(参考 Python: how to import from all modules in dir?

from lib import *

但遇到问题 TypeError: 'module' object is not callable。更具体地说,在 main.py:

#!/usr/bin/env python

from lib import * # cause: TypeError: 'module' object is not callable
#from lib.DominatingSets import *   # it works

dominatingSets = DominatingSets()

完整的异常回溯:

$ python main.py 
Traceback (most recent call last):
  File "main.py", line 6, in <module>
    dominatingSets = DominatingSets()
TypeError: 'module' object is not callable

树状格式的目录。

$ tree -P '*.py' .
.
├── __init__.py
├── lib
│   ├── AnalyzeGraph.py
│   ├── AutoVivification.py
│   ├── DominatingSets.py
│   ├── __init__.py
│   ├── Output.py
│   ├── PlotGraph.py
│   ├── ProcessDatasets.py
│   └── ReadGTFS.py
├── main.py

lib/__init__.py内容如下。 (参考Loading all modules in a folder in Python

from os.path import dirname, basename, isfile
import glob
modules = glob.glob(dirname(__file__)+"/*.py")
__all__ = [ basename(f)[:-3] for f in modules if isfile(f) and not basename(f).startswith('__')] # exclude __init__.py

发生这种混淆的部分原因是您的模块名称与您要从中加载的 classes 的名称相同。 (至少,这就是让它变得更加混乱的原因。)您的代码确实正确加载了 classes 所在的模块。但是,它不会从这些模块中加载 classes,并且这就是你真正想做的。

因为你的 class DominatingSets 在模块 lib.DominatingSets 中,它从根目录的完整路径是 lib.DominatingSets.DominatingSets.

from lib import *

在你的情况下会做与

相同的事情
from lib import DominatingSets
from lib import AnalyzeGraph
# ...

然而,

from lib import DominatingSets

等同于

import lib.DominatingSets
DominatingSets = lib.DominatingSets

lib.DominatingSets 是一个 模块 (lib/DominatingSets.py),而不是您想要的 class。

from lib.DominatingSets import DominatingSets

等同于

import lib.DominatingSets
DominatingSets = lib.DominatingSets.DominatingSets

这就是它起作用的原因:这是您要导入到名称 DominatingSets 中的 class。

如果你想让from lib import *导入子模块中的所有class,你需要将这些class导入到lib模块中。例如,在 lib/__init__.py:

from DominatingSets import *
from AnalyzeGraph import *
# ...

在您进行更改时,我建议(像其他人一样)使用正常的 Python 命名约定,并将您的模块名称小写:将 DominatingSets.py 更改为 dominatingsets.py.那么这段代码就会变成

from dominatingsets import *
from analyzegraph import *
# ...

看你的Traceback,我想你的问题可能出在这里:

首先我们来看一个例子:

import datetime
d = datetime(2005, 23, 12)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'module' object is not callable

基本上,我们刚刚导入了整个 datetime 模块,我们试图像模块中的 class 对象一样调用它。让我们现在做:

k = datetime.datetime(2005, 12, 22)
print k
2005-12-22 00:00:00

这次没问题,因为我们在 datetime 模块中引用 datetime 对象类型

如果我们这样做:

from datetime import datetime
datetime
<type 'datetime.datetime'>

我们再次到达所需的对象,因为我们在 datetime 模块中导入 datetime class。 另外,使用 *

from datetime import *
d = datetime(2005, 3, 12)

也可以工作,因为您正在导入 datetime 模块中的所有 classes。

你的代码说:

from lib import * # This imports all MODULES within lib, not the classes
#from lib.DominatingSets import *   # it works because you import the classes within the DominatingSets Module

您可以使用 from lib.DominatingSets import DominatingSets 来解决您的问题,或者如果您坚持使用 from lib import *,请将代码更改为 dominatingsets = DominatingSets.DominatingSets()

希望对您有所帮助!

我从这里的 中学到了很多东西...但是如果这个目录 lib 实际上没有包含在 PYTHONPATH 中,我仍然对将什么放入 lib/__init__.py 文件有疑问.

我发现除了在caller文件中添加lib的父目录,即

sys.path.append( '.../parent_dir_of_lib' )

我要么 1) 必须在调用者文件中此外执行此操作:

sys.path.append( '.../parent_dir_of_lib/lib' )

或 2) 必须使 lib 目录“自加载”,方法是将其放入 __init__.py:

import sys
from pathlib import Path
parent_dir_str = str( Path(__file__).resolve().parent )
sys.path.append( parent_dir_str )
 
from analyse_graph import *
from auto_vivification import *
...