有没有一种简单的方法来查找属于Python包的所有模块?我找到了这个旧的讨论,但它并不是很确定。在我基于os.listdir()推出自己的解决方案之前,我想有一个明确的答案。
是的,你需要使用pkgutil
或类似方法来处理所有的包,不管它们是在蛋文件(eggs)还是压缩文件(zips)中(这些情况下,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
是什么?我能用它来导入一个模块吗,而不是使用似乎有些“笨拙”的__import__(modname, fromlist="dummy")
吗? - MestreLionm = importer.find_module(modname).load_module(modname)
,然后m
就是模块,例如:m.myfunc()
。 - chrisleague__path__
属性的 Python 模块。” - 因此我们只能从包中获取路径,而不能从任何模块中获取。 - augustomen这项工作的正确工具是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
方法:http://docs.python.org/library/pkgutil.html#pkgutil.walk_packages。 - Mechanical snail这对我有用:
import types
for key, obj in nltk.__dict__.iteritems():
if type(obj) is types.ModuleType:
print key
def list_submodules(module) -> list[str]:
"""
Args:
module: The module to list submodules from.
"""
# We first respect __all__ attribute if it already defined.
submodules = getattr(module, "__all__", None)
if submodules:
return submodules
# Then, we respect module object itself to get imported submodules.
# Warning: Initially, the module object will respect the `__init__.py`
# file, if its not exists, the object can partially load submoudles
# by coda, so can lead `inspect` to return incomplete submodules list.
import inspect
submodules = [o[0] for o in inspect.getmembers(module)
if inspect.ismodule(o[1])]
if submodules:
return submodules
# Finally we can just scan for submodules via pkgutil.
import pkgutil
# pkgutill will invoke `importlib.machinery.all_suffixes()`
# to determine whether a file is a module, so if you get any
# submoudles that are unexpected to get, you need to check
# this function to do the confirmation.
# If you want to retrive a directory as a submoudle, you will
# need to clarify this by putting a `__init__.py` file in the
# folder, even for Python3.
return [x.name for x in pkgutil.iter_modules(module.__path__)]
import module
print(list_submodules(module))
path = ...
module = importlib.import_module(path)
print(list_submodules(module))
我正在寻找一种重新加载我正在实时编辑的包中所有子模块的方法。 这是上面答案/评论的结合体,所以我决定将其作为答案发布在这里而不是作为评论。
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
文件中被引入,因此这取决于您对“包的一部分”是什么意思。