Ответ 1
используя dir() и imp module
Хотя в Python довольно сложно вводить "дочерний" модуль в другой модуль и перечислять его атрибуты, становится немного сложнее, если вы хотите импортировать все дочерние модули.
Я создаю библиотеку инструментов для существующего 3D-приложения. Каждый инструмент имеет свой собственный пункт меню и подменю. Я хотел бы, чтобы инструмент отвечал за создание собственного меню, поскольку многие из них меняются в зависимости от контекста и шаблонов. Я хочу, чтобы мой базовый модуль мог найти все дочерние модули и проверить функцию create_menu()
и вызвать его, если он найдет его.
Каков самый простой способ обнаружить все дочерние модули?
используя dir() и imp module
Я думаю, что лучший способ сделать этот вид плагина - использовать entry_points
и API для запроса.
Когда я был добрым и только начинал программировать на Python, я написал это для моего модульного IRC-бота:
# Load plugins
_plugins = []
def ifName(name):
try:
return re.match('([^_.].+)\.[^.]+', a).group(1)
except:
return None
def isValidPlugin(obj):
from common.base import PluginBase
try:
if obj.__base__ == PluginBase:
return True
else:
return False
except:
return False
plugin_names = set(ifilter(lambda a: a!=None, [ifName(a) for a in os.listdir(os.path.join(os.getcwd(), 'plugins'))]))
for plugin_name in plugin_names:
try:
plugin = __import__('plugins.'+plugin_name, fromlist=['plugins'])
valid_plugins = filter(lambda a: isValidPlugin(a), [plugin.__getattribute__(a) for a in dir(plugin)])
_plugins.extend(valid_plugins)
except Exception, e:
logger.exception('Error loading plugin %s', plugin_name)
# Run plugins
_plugins = [klass() for klass in _plugins]
Это не безопасный или "правильный" способ, но, возможно, это будет полезно. Это очень старый код, поэтому, пожалуйста, не бить меня.
Решение выше, перемещая файловую систему для поиска подмодулей, нормально, пока вы реализуете каждый плагин как модуль на основе файловой системы.
Более гибким способом будет явный список плагинов в вашем основном модуле и каждый плагин (будь то модуль, созданный файлом, динамически или даже экземпляр класса), добавляя себя в этот список явно. Может быть, через функцию registerPlugin.
Помните: "Явное лучше, чем неявное" является частью zen python.
Вы можете попробовать glob
bing каталог:
import os
import glob
modules = glob.glob(os.path.join('/some/path/to/modules', '*.py'))
Затем вы можете попробовать импортировать их:
checked_modules
for module in modules:
try:
__import__(module, globals(), locals()) # returns module object
except ImportError:
pass
else:
checked_modules.append(module)