Существует ли стандартный способ перечисления имен модулей Python в пакете? - PullRequest
82 голосов
/ 28 января 2009

Существует ли простой способ перечисления имен всех модулей в пакете, без использования __all__?

Например, с учетом этого пакета:

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

Мне интересно, есть ли стандартный или встроенный способ сделать что-то вроде этого:

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

Ручной подход состоит в том, чтобы перебирать пути поиска модуля, чтобы найти каталог пакета. Затем можно перечислить все файлы в этом каталоге, отфильтровать файлы с уникальным именем py / pyc / pyo, удалить расширения и вернуть этот список. Но это кажется достаточным количеством работы для чего-то, что механизм импорта модулей уже выполняет внутри. Эта функциональность доступна где-нибудь?

Ответы [ 10 ]

172 голосов
/ 21 августа 2009

Используя python2.3 и выше , вы также можете использовать модуль pkgutil:

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

РЕДАКТИРОВАТЬ: Обратите внимание, что параметр не список модулей, а список путей, поэтому вы можете захотеть сделать что-то вроде этого:

>>> import os.path, pkgutil
>>> import testpkg
>>> pkgpath = os.path.dirname(testpkg.__file__)
>>> print [name for _, name, _ in pkgutil.iter_modules([pkgpath])]
25 голосов
/ 29 января 2009
import module
help(module)
18 голосов
/ 29 января 2009

Может быть, это сделает то, что вы ищете?

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)])
7 голосов
/ 05 апреля 2013

Не знаю, пропускаю ли я что-то или ответы просто устарели, но;

Как указано пользователем 815423426, это работает только для живых объектов, и перечисленные модули являются только модулями, которые были импортированы ранее.

Список модулей в пакете кажется действительно простым, используя inspect :

>>> import inspect, testpkg
>>> inspect.getmembers(testpkg, inspect.ismodule)
['modulea', 'moduleb']
2 голосов
/ 13 октября 2017

Это рекурсивная версия, которая работает с 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
0 голосов
/ 22 марта 2019

Если вы хотите просмотреть информацию о вашем пакете вне кода Python (из командной строки), вы можете использовать для него pydoc.

# get a full list of packages that you have installed on you machine
$ python -m pydoc modules

# get information about a specific package
$ python -m pydoc <your package>

У вас будет тот же результат, что и у pydoc, но внутри интерпретатора с помощью справки

>>> import <my package>
>>> help(<my package>)
0 голосов
/ 19 января 2019

Здесь должны быть перечислены модули:

help("modules")
0 голосов
/ 21 апреля 2016

Основываясь на примере cdleary, вот рекурсивный путь перечисления версий для всех подмодулей:

import imp, os

def iter_submodules(package):
    file, pathname, description = imp.find_module(package)
    for dirpath, _, filenames in os.walk(pathname):
        for  filename in filenames:
            if os.path.splitext(filename)[1] == ".py":
                yield os.path.join(dirpath, filename)
0 голосов
/ 25 марта 2009
def package_contents(package_name):
  package = __import__(package_name)
  return [module_name for module_name in dir(package) if not module_name.startswith("__")]
0 голосов
/ 28 января 2009

print dir (модуль)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...