119

有没有一种简单的方法可以找到作为 python 包一部分的所有模块?我发现了这个旧的讨论,这并不是真正的结论,但在我推出基于 os.listdir() 的自己的解决方案之前,我很想有一个明确的答案。

4

5 回答 5

161

是的,你想要一些基于pkgutil或类似的东西——这样你就可以对待所有的包,不管它们是在鸡蛋里还是在拉链里(os.listdir 无济于事)。

import pkgutil

# this is the package we are inspecting -- for example 'email' from stdlib
import email

package = email
for importer, modname, ispkg in pkgutil.iter_modules(package.__path__):
    print "Found submodule %s (is a package: %s)" % (modname, ispkg)

如何导入它们呢?您可以__import__正常使用:

import pkgutil

# this is the package we are inspecting -- for example 'email' from stdlib
import email

package = email
prefix = package.__name__ + "."
for importer, modname, ispkg in pkgutil.iter_modules(package.__path__, prefix):
    print "Found submodule %s (is a package: %s)" % (modname, ispkg)
    module = __import__(modname, fromlist="dummy")
    print "Imported", module
于 2009-11-10T12:58:55.073 回答
52

适合这项工作的工具是 pkgutil.walk_packages。

要列出系统上的所有模块:

import pkgutil
for importer, modname, ispkg in pkgutil.walk_packages(path=None, onerror=lambda x: None):
    print(modname)

请注意 walk_packages 导入所有子包,但不导入子模块。

如果你想列出某个包的所有子模块,那么你可以使用这样的东西:

import pkgutil
import scipy
package=scipy
for importer, modname, ispkg in pkgutil.walk_packages(path=package.__path__,
                                                      prefix=package.__name__+'.',
                                                      onerror=lambda x: None):
    print(modname)

iter_modules 仅列出一级深度的模块。walk_packages 获取所有子模块。以 scipy 为例,walk_packages 返回

scipy.stats.stats

而 iter_modules 只返回

scipy.stats

pkgutil 的文档 ( http://docs.python.org/library/pkgutil.html ) 没有列出 /usr/lib/python2.6/pkgutil.py 中定义的所有有趣的函数。

也许这意味着这些功能不是“公共”界面的一部分,并且可能会发生变化。

但是,至少从 Python 2.6(可能还有更早的版本?)开始,pkgutil 带有一个 walk_packages 方法,它递归地遍历所有可用的模块。

于 2009-11-10T15:15:48.003 回答
2

这对我有用:

import types

for key, obj in nltk.__dict__.iteritems():
    if type(obj) is types.ModuleType: 
        print key
于 2013-03-30T20:24:30.500 回答
0

我正在寻找一种方法来重新加载我在包中实时编辑的所有子模块。它是上述答案/评论的组合,所以我决定在这里发布它作为答案而不是评论。

package=yourPackageName
import importlib
import pkgutil
for importer, modname, ispkg in pkgutil.walk_packages(path=package.__path__, prefix=package.__name__+'.', onerror=lambda x: None):
    try:
        modulesource = importlib.import_module(modname)
        reload(modulesource)
        print("reloaded: {}".format(modname))
    except Exception as e:
        print('Could not load {} {}'.format(modname, e))
于 2019-11-03T03:46:05.187 回答
-4

这是我想到的一种方法:

>>> import os
>>> filter(lambda i: type(i) == type(os), [getattr(os, j) for j in dir(os)])
[<module 'UserDict' from '/usr/lib/python2.5/UserDict.pyc'>, <module 'copy_reg' from '/usr/lib/python2.5/copy_reg.pyc'>, <module 'errno' (built-in)>, <module 'posixpath' from '/usr/lib/python2.5/posixpath.pyc'>, <module 'sys' (built-in)>]

它当然可以清理和改进。

编辑:这是一个稍微好一点的版本:

>>> [m[1] for m in filter(lambda a: type(a[1]) == type(os), os.__dict__.items())]
[<module 'copy_reg' from '/usr/lib/python2.5/copy_reg.pyc'>, <module 'UserDict' from '/usr/lib/python2.5/UserDict.pyc'>, <module 'posixpath' from '/usr/lib/python2.5/posixpath.pyc'>, <module 'errno' (built-in)>, <module 'sys' (built-in)>]
>>> [m[0] for m in filter(lambda a: type(a[1]) == type(os), os.__dict__.items())]
['_copy_reg', 'UserDict', 'path', 'errno', 'sys']

注意:这还将找到可能不一定位于包的子目录中的模块,如果它们被拉入其__init__.py文件中,那么这取决于您所说的“部分”包的含义。

于 2009-11-10T12:54:03.677 回答