Python импортирует классы из модулей динамически
Я работаю с API, который имеет много подкомпонентов. Я делаю инструментарий для взаимодействия с этим API, и я хотел бы сделать так, чтобы я мог динамически загружать некоторые классы на основе переменных, например, загружая все классы, которые имеют переменную api_module = True, установленную внутри.
.
├── APIModules
│ ├── ccu.py
│ ├── __init__.py
│ └── OpenAPI.py
Класс CCU в файле ccu
class CCU:
api_module = True
actions = ['post_new_purge','get_purge_queue','get_purge_status']
Это поможет мне динамически документировать и расширять набор инструментов по мере добавления новых классов без необходимости поддерживать списки импорта при каждом добавлении нового подкомпонента. Есть простой способ сделать это?
Я знаю, что могу получить список всех файлов python в каталоге APIModules с глобусом, но затем я хочу загрузить и проверить все классы в файлах, не зная, как они могут быть вызваны.
import os
import glob
modules = glob.glob(os.path.dirname(__file__)+"/*.py")
2 ответа
Вы можете использовать метаклассы вместе с реестром классов для отслеживания любых новых классов, которые добавляются в систему.
Здесь есть пошаговое руководство, которое должно предоставить вам необходимую помощь http://effbot.org/zone/metaclass-plugins.htm
Является ли это хорошей идеей, это другой вопрос (я думаю, что sqlalchemy использует этот шаблон для декларативной базы, и он работает хорошо).
# from http://effbot.org/zone/metaclass-plugins.htm
registry = [] # list of subclasses
class Plugin(object):
class __metaclass__(type):
def __init__(cls, name, bases, dict):
type.__init__(name, bases, dict)
registry.append((name, cls))
# in your plugin modules
class SpamPlugin(Plugin):
pass
class BaconPlugin(Plugin):
pass
# in your plugin loader
# import all plugin modules
# loop over registered plugins
for name, cls in registry:
if cls is not Plugin:
print name, cls
# here you could check various attributes of the class to
# see if it was one you wanted to use
Edit Я думаю, что я немного неправильно понял - вы не хотите импортировать модули один за другим - но вы могли бы написать что-нибудь, чтобы импортировать все файлы в папке api. Тогда каждый из классов будет наследоваться от базового класса API, который поддерживает реестр. Когда вы хотите работать с чем-либо, вы заходите в реестр, чтобы найти интересующие вас классы.
Поскольку вам нужно будет импортировать класс для чтения его атрибутов, и вы пытаетесь выяснить, следует ли вам импортировать его в первую очередь, у вас есть ловушка 22 здесь.
Это оставляет вас с подходом синтаксического анализа файла.py с другими методами и решения, основанного на этом, импортировать ли рассматриваемый модуль или нет. Но этот подход также грязный и слишком сложный.
Я думаю, что самый простой подход - полностью изменить точку зрения. Вместо того, чтобы иметь api_module = True
Внутри каждого модуля вы можете просто иметь один список активных модулей внутри вашего основного приложения и выбирать на основе этого:
api_modules = ["module_1", "module_2", "module_3"]
Это уменьшает объем обслуживания (вам нужно поддерживать только одну строку кода) и обеспечивает такую же степень гибкости.