Есть ли простой способ найти все модули, которые являются частью пакета python? Я нашел this old discussion, что на самом деле не является окончательным, но я хотел бы получить конкретный ответ, прежде чем выпустить собственное решение на основе os.listdir().Список всех модулей, входящих в пакет python?
ответ
Да, вы хотите что-то, основанное на pkgutil
или аналогичном - таким образом вы можете обрабатывать все пакеты, независимо от того, находятся ли они в яйцах или почтовых индексах или так (где 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'? Могу ли я использовать его для импорта модуля вместо использования этого, казалось бы, «хакерского» '__import __ (modname, fromlist =" dummy ")'? – MestreLion
Я смог использовать импортер следующим образом: 'm = importer.find_module (modname) .load_module (modname)', а затем 'm' является модулем, например, например:' m.myfunc() ' – chrisleague
@chrisleague I использовал метод ur с python 2.7, но теперь мне нужно перейти на python 3.4, так что вы знаете, что в python 3 pkutil.iter_modules дает (module_finder, name, ispkg) вместо (module_loader, name, ispkg). Что я могу сделать, чтобы он работал как предыдущий? –
Вот один из способов, с верхней частью моей головы:
>>> 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)>]
Это, безусловно, может быть очищено и улучшено.
EDIT: Вот немного лучше версия:
>>> [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
, так что это зависит от того, что вы подразумеваете под «частью» пакета.
извините, это бесполезно. Помимо ложных срабатываний, он найдет только уже импортированные подмодули пакетов. – u0b34a0f6ae
Правильный инструмент для этой работы является 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 –
Ваш второй пример вызывает следующую ошибку: **« AttributeError: ' модуль 'не имеет атрибута' __path __ '"** - Я не тестировал его с помощью scipy, но с несколькими другими пакетами. Это что-то связано с версией Python? (Я использую Python 2.7) – Apostolos
@Apostolos: должно быть два символа подчеркивания ('_') до и после' path' - то есть [use 'package .__ path__'] (https://stackoverflow.com/q/ 2699287/190597), а не 'package._path_'. Возможно, было бы проще попробовать вырезать и вставлять код, а не повторно вводить его. – unutbu
Это работает для меня:
import types
for key, obj in nltk.__dict__.iteritems():
if type(obj) is types.ModuleType:
print key
бонусный вопрос: как вы импортировать найденные модули красиво? –
Что не так с чтением исходного каталога? Какая еще информация вам нужна? Что случилось с 'ls' (или' dir')? –
@ S.Lott: Доступны более общие решения, пакеты python не всегда находятся в каталогах в файловой системе, но также могут быть внутри zips. – u0b34a0f6ae