Чи є прямий спосіб знайти всі модулі, що входять до пакету python? Я знайшов цю стару дискусію , яка насправді не є переконливою, але я хотів би отримати певну відповідь, перш ніж розгорнути власне рішення на основі os.listdir ().
Чи є прямий спосіб знайти всі модулі, що входять до пакету python? Я знайшов цю стару дискусію , яка насправді не є переконливою, але я хотів би отримати певну відповідь, перш ніж розгорнути власне рішення на основі os.listdir ().
Відповіді:
Так, ви хочете щось на основі 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
importer
повертається pkgutil.iter_modules
? Чи можу я використовувати його для імпорту модуля замість того, щоб використовувати цей, здавалося б, "хакічний" __import__(modname, fromlist="dummy")
?
m = importer.find_module(modname).load_module(modname)
а далі m
- модуль, наприклад:m.myfunc()
_path_
). З обох боків повинно бути два (всього чотири __path__
).
Правильним інструментом для цього завдання є 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
тепер знаходиться в документації: docs.python.org/library/pkgutil.html#pkgutil.walk_packages
_
і після path
цього повинно бути дві підкреслення ( ) , тобто скоріше використовуватиpackage.__path__
package._path_
. Можливо, буде простіше спробувати вирізати та вставити код, а не повторно вводити його.
package
вказує на пакет, а не на модуль. Модулі - це файли, тоді як пакети - це каталоги. Усі пакети мають __path__
атрибут (... якщо хтось не видалив атрибут з якоїсь причини.)
Це працює для мене:
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)>]
Це, безумовно, можна було почистити та покращити.
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
файл, тому це залежить від того, що ви маєте на увазі під "частиною" пакета.