Перечислите все модули, которые являются частью пакета Python?
Есть ли простой способ найти все модули, которые являются частью пакета Python? Я нашел это старое обсуждение, которое на самом деле не является окончательным, но я бы хотел получить определенный ответ, прежде чем я разверну свое собственное решение, основанное на os.listdir().
4 ответа
Да, вы хотите что-то на основе 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.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, который рекурсивно просматривает все доступные модули.
Это работает для меня:
import types
for key, obj in nltk.__dict__.iteritems():
if type(obj) is types.ModuleType:
print key
Я искал способ перезагрузить все подмодули, которые я редактирую прямо в своем пакете. Это комбинация ответов / комментариев выше, поэтому я решил опубликовать ее здесь в качестве ответа, а не комментария.
package=yourPackageName
import importlib
import pkgutil
for importer, modname, ispkg in pkgutil.walk_packages(path=package.__path__, prefix=package.__name__+'.', onerror=lambda x: None):
try:
modulesource = importlib.import_module(modname)
reload(modulesource)
print("reloaded: {}".format(modname))
except Exception as e:
print('Could not load {} {}'.format(modname, e))
Вот один из способов, от макушки моей головы:
>>> 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)>]
Это, безусловно, может быть очищено и улучшено.
РЕДАКТИРОВАТЬ: Вот немного лучше версия:
>>> [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
файл, так что это зависит от того, что вы подразумеваете под "частью" пакета.