Есть ли стандартный способ перечислить имена модулей Python в пакете?
Есть ли простой способ перечислить имена всех модулей в пакете без использования __all__
?
Например, данный пакет:
/testpkg
/testpkg/__init__.py
/testpkg/modulea.py
/testpkg/moduleb.py
Мне интересно, есть ли стандартный или встроенный способ сделать что-то вроде этого:
>>> package_contents("testpkg")
['modulea', 'moduleb']
Ручным подходом было бы перебирать пути поиска модулей, чтобы найти каталог пакетов. Затем можно было бы перечислить все файлы в этом каталоге, отфильтровать файлы с именами py/pyc/pyo с уникальным именем, удалить расширения и вернуть этот список. Но это похоже на хорошую работу над чем-то, что механизм импорта модулей уже делает внутренне. Является ли эта функциональность открытой в любом месте?
Ответы
Ответ 1
Возможно, это сделает то, что вы ищете?
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)])
Ответ 2
Используя python2.3 и выше, вы также можете использовать модуль pkgutil
:
>>> import pkgutil
>>> [name for _, name, _ in pkgutil.iter_modules(['testpkg'])]
['modulea', 'moduleb']
EDIT: Обратите внимание, что параметр не является списком модулей, а списком путей, поэтому вы можете сделать что-то вроде этого:
>>> import os.path, pkgutil
>>> import testpkg
>>> pkgpath = os.path.dirname(testpkg.__file__)
>>> print [name for _, name, _ in pkgutil.iter_modules([pkgpath])]
Ответ 3
import module
help(module)
Ответ 4
Не знаю, не замечу ли я что-то, или если ответы только устарели, но
Как указано пользователем815423426, это работает только для живых объектов, а перечисленные модули - это только модули, которые ранее были импортированы.
Листинг модулей в пакете кажется очень простым, используя inspect:
>>> import inspect, testpkg
>>> inspect.getmembers(testpkg, inspect.ismodule)
['modulea', 'moduleb']
Ответ 5
Это рекурсивная версия, которая работает с python 3.6 и выше:
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
Ответ 6
Основываясь на примере cdleary, здесь приведен путь рекурсивной версии для всех подмодулей:
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)
Ответ 7
Это должно перечислить модули:
help("modules")
Ответ 8
print dir (module)
Ответ 9
def package_contents(package_name):
package = __import__(package_name)
return [module_name for module_name in dir(package) if not module_name.startswith("__")]