列出作为 python 包一部分的所有模块?

Posted

技术标签:

【中文标题】列出作为 python 包一部分的所有模块?【英文标题】:List all the modules that are part of a python package? 【发布时间】:2010-12-15 00:42:04 【问题描述】:

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

【问题讨论】:

@S.Lott:有更通用的解决方案可用,python 包并不总是在文件系统的目录中,但也可以在 zip 中。 为什么要重新发明***?如果 python 在 Python 4、pkgutil 中获取超模块并使用它进行更新,我的代码仍然可以工作。我喜欢使用可用的抽象。使用提供的显而易见的方法,它经过测试并且已知有效。重新实现.. 现在您必须自己找到并解决每个角落案例。 @S.Lott:所以每次应用程序启动时,如果安装在其中,它会解压缩自己的鸡蛋来检查这一点?请针对我的项目提交一个补丁,以在此功能中重新发明***:git.gnome.org/cgit/kupfer/tree/kupfer/plugins.py#n17。请考虑鸡蛋和普通目录,不要超过 20 行。 @S.Lott:为什么你不明白它是相关的,这是你无法理解的。以编程方式发现这一点是因为 应用程序 对包的内容感兴趣,而不是用户。 当然我的意思是编程!否则我不会提到“使用 os.listdir() 推出我自己的解决方案” 【参考方案1】:

是的,您想要基于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

【讨论】:

pkgutil.iter_modules 返回的importer 是什么?我可以用它来导入模块而不是使用这个看似“hackish”的__import__(modname, fromlist="dummy") 吗? 我可以像这样使用导入器:m = importer.find_module(modname).load_module(modname) 然后m 是模块,例如:m.myfunc() @chrisleague 我在 python 2.7 中使用了你的方法,但现在我需要继续使用 python 3.4,所以你知道在 python 3 pkutil.iter_modules 产生 (module_finder, name, ispkg) 而不是(模块加载器,名称,ispkg)。我该怎么做才能让它像以前一样工作? 您的第一个示例产生以下错误:"AttributeError: 'module' object has no attribute '_path_'" 与此有什么关系Python版本? (我使用 Python 2.7) @Apostolos,您在路径的任一侧只使用了一个下划线(即_path_)。两边应该有两个,总共四个(即__path__)。【参考方案2】:

适合这项工作的工具是 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 方法,它递归地遍历所有 可用的模块。

【讨论】:

walk_packages 现在在文档中:docs.python.org/library/pkgutil.html#pkgutil.walk_packages 您的第二个示例产生以下错误:"AttributeError: 'module' object has no attribute '_path_'" - 我没有测试它与“scipy”一起使用,但与其他一些软件包一起使用。这与Python版本有什么关系吗? (我使用 Python 2.7) @Apostolos:path 前后应该有两个下划线(_)——即use package.__path__,而不是package._path_。尝试剪切和粘贴代码可能比重新键入更容易。 我写评论的时候有两个! :) 但它们已被系统剥离。我的错;我应该放三个下划线。但是,如果我想使用斜体就可以了,但我没有! ......这是一个损失损失的情况。 :) 无论如何,当我运行代码时,我当然使用了其中的两个。 (我复制粘贴了代码。) @Apostolos:确保变量package 指向一个包,而不是一个模块。模块是文件,而包是目录。 All packages have the __path__ attribute(...除非有人出于某种原因删除了该属性。)【参考方案3】:

这对我有用:

import types

for key, obj in nltk.__dict__.iteritems():
    if type(obj) is types.ModuleType: 
        print key

【讨论】:

这在两种情况下会失败 1. 包并不总是将其子模块显式导入***命名空间 2. 包可能会将其他 3rd-party 模块导入其***命名空间【参考方案4】:

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

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))

【讨论】:

【参考方案5】:

这是我想不到的一种方法:

>>> 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 文件中,这也会找到可能不一定位于包的子目录中的模块,所以这取决于你的意思包的“一部分”。

【讨论】:

对不起,这没有用。除了误报,它也只会找到已经导入的包子模块。

以上是关于列出作为 python 包一部分的所有模块?的主要内容,如果未能解决你的问题,请参考以下文章

列出一个项目导入的所有python模块

如何列出 Python 模块中的所有函数?

如何列出 Python 模块中的所有函数?

python Python脚本列出给定Python包的所有子模块

如何在 Python 中列出所有已安装的包及其版本?

如何使用 python.logging 模块列出所有现有的记录器