有没有一种标准的方式来列出包中的Python模块名称?

有没有一种直接的方式来列出包中的所有模块的名称,而不使用__all__

例如,给定这个包:

 /testpkg /testpkg/__init__.py /testpkg/modulea.py /testpkg/moduleb.py 

我想知道是否有标准或内置的方式来做这样的事情:

 >>> package_contents("testpkg") ['modulea', 'moduleb'] 

手动方法是遍历模块searchpath,以查找包的目录。 然后可以列出该目录中的所有文件,过滤出唯一命名的py / pyc / pyo文件,剥离扩展名并返回该列表。 但是对于模块导入机制已经在内部进行的工作来说,这似乎是相当多的工作。 这个function暴露在哪里?

也许这会做你想要的?

 import imp import os MODULE_EXTENSIONS = ('.py', '.pyc', '.pyo') def package_contents(package_name): file, pathname, description = imp.find_module(package_name) if file: raise ImportError('Not a package: %r', package_name) # Use a set because some may be both source and compiled. return set([os.path.splitext(module)[0] for module in os.listdir(pathname) if module.endswith(MODULE_EXTENSIONS)]) 

使用python2.3及以上版本 ,你也可以使用pkgutil模块:

 >>> import pkgutil >>> [name for _, name, _ in pkgutil.iter_modules(['testpkg'])] ['modulea', 'moduleb'] 

编辑:请注意,该参数不是模块的列表,而是一个path列表,所以你可能想要做这样的事情:

 >>> import os.path, pkgutil >>> import testpkg >>> pkgpath = os.path.dirname(testpkg.__file__) >>> print [name for _, name, _ in pkgutil.iter_modules([pkgpath])] 
 import module help(module) 

不知道我是否忽略了某些东西,或者如果答案只是过时了,

如user815423426所述,这仅适用于活动对象,列出的模块只是之前导入的模块。

使用inspect在软件包中列出模块看起来非常简单:

 >>> import inspect, testpkg >>> inspect.getmembers(testpkg, inspect.ismodule) ['modulea', 'moduleb'] 

基于cdleary的例子,下面是所有子模块的recursion版本列表path:

 import imp, os def iter_submodules(package): file, pathname, description = imp.find_module('isc_datasources') for dirpath, _, filenames in os.walk(pathname): for filename in filenames: if os.path.splitext(filename)[1] == ".py": yield os.path.join(dirpath, filename) 

这是一个与Python 3.6及以上版本兼容的recursion版本:

 import importlib.util from pathlib import Path import os MODULE_EXTENSIONS = '.py' def package_contents(package_name): spec = importlib.util.find_spec(package_name) if spec is None: return set() pathname = Path(spec.origin).parent ret = set() with os.scandir(pathname) as entries: for entry in entries: if entry.name.startswith('__'): continue current = '.'.join((package_name, entry.name.partition('.')[0])) if entry.is_file(): if entry.name.endswith(MODULE_EXTENSIONS): ret.add(current) elif entry.is_dir(): ret.add(current) ret |= package_contents(current) return ret 

打印目录(模块)

 def package_contents(package_name): package = __import__(package_name) return [module_name for module_name in dir(package) if not module_name.startswith("__")]