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"]

Это уменьшает объем обслуживания (вам нужно поддерживать только одну строку кода) и обеспечивает такую ​​же степень гибкости.

Другие вопросы по тегам