有没有一种直接的方法来查找python软件包中的所有模块?我已经找到了这个旧的讨论,这并不是真正的结论,但是我很想在我基于os.listdir()推出自己的解决方案之前有一个明确的答案。
有没有一种直接的方法来查找python软件包中的所有模块?我已经找到了这个旧的讨论,这并不是真正的结论,但是我很想在我基于os.listdir()推出自己的解决方案之前有一个明确的答案。
Answers:
是的,您需要某种基于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
importer
由pkgutil.iter_modules
什么返回的?我可以使用它来导入模块,而不是使用这个看似“ hackish”的模块__import__(modname, fromlist="dummy")
吗?
m = importer.find_module(modname).load_module(modname)
然后m
是模块,例如:m.myfunc()
_path_
)仅使用一个下划线。两侧应有两个,总共四个(即__path__
)。
这项工作的正确工具是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
package
指向软件包,而不是模块。模块是文件,而包是目录。所有软件包都具有__path__
属性(...,除非有人出于某种原因删除了该属性。)
我一直在寻找一种方法来重新加载我正在编辑的程序包中的所有子模块。它是上述答案/评论的组合,因此我决定将其发布在此处,作为答案而不是评论。
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))
这是我的头上的一种方法:
>>> 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
文件中,它们也将找到不一定位于包子目录中的模块,因此取决于您“包的一部分”的含义。