有没有一种标准的方式来列出包中的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("__")]