2013-12-19 4 views
1

Мой проект должен быть расширяемым, у меня есть много скриптов с тем же интерфейсом, что и поиск в Интернете. Перед тем как я использовал __import__ но это не позволяет мне поставить свои «плагин» на выделенный каталоге:python 3 import from subdir

root/ 
    main.py 
    plugins/ 
     [...] 

Так что мой вопрос: Есть ли способ, чтобы индивидуально импортировать модули из этого подкаталога? Я предполагаю, что importlib, но я так потерял в том, как работает процесс загрузки модуля Python ... Что я хочу сделать что-то вроде этого:

for pluginname in plugins: 
    plugin = somekindofimport("plugins/{name}".format(name=pluginname)) 
    plugin.unififedinterface() 

Кроме того, в качестве побочного вопроса, путь утра Я пытаюсь добиться расширяемости - это хороший способ?

Я на python3.3

ответ

3

Стоп мышления с точки зрения имен путей и начать думать в терминах пакетов. Прочтите Packages в учебнике, и если вы хотите более подробно, см. The import system.

Но основная идея заключается в следующем:

Создать имя файла plugins/__init__.py. Он может быть пустым; этого достаточно, чтобы включить plugins в пакет . Это означает, что вы можете импортировать модули из этого пакета с помощью:

import plugins.plugin 

Итак, как вы это делаете динамически? Вот для чего importlib. (Вы также можете использовать __import__ здесь, но это менее гибкий и менее читаемым в нетривиальных случаях, поэтому если вам не нужно предварительно 3.3 совместимости, нет.)

plugin = importlib.import_module('plugins.{name}'.format(name=pluginname)) 

Это, вероятно, будет чище для import plugins для получения пакета, а затем использовать относительный импорт из этого пакета, как показано в примерах в документах import_module.

Это также означает, что Python заботится о .pyc создания и кэширования и т.д.

А это значит, что вы можете позже расширить plugins быть «пространство имен пакета», который может быть разделен на несколько каталогов, как /usr/share/myapp/plugins для платных плагинов, /etc/myapp/plugins для плагинов сайта и ~/myapp/plugins для пользовательских плагинов.


Если вы действительно, действительно хотите импортировать из каталога, который не является пакет, вы можете создать модуль загрузчика и использовать его, но это в целом много работы не реальной пользы. (На самом деле это не так сложно в 3.3 (SourceLoader, и друзья будут делать большую часть работы за вас), но вы не найдете практически никаких примеров для руководства, вместо этого вы найдете примеры пути 2.6-3.2 или 2.0-2.5, оба из которых - это.) Кроме того, это означает, что если кто-то создает плагин с именем, скажем, gzip, вы можете в конечном итоге заблокировать модуль stdlib gzip с помощью плагина. (Это особенно забавно, если плагин gzip пытается использовать модуль stdlib , так как он, вероятно, будет ...) Если плагин заканчивается именем plugins.gzip, проблем нет.


Кроме того, в качестве побочного вопроса, то, как я пытаюсь достичь расширяемости это хороший способ?

Пока вы только хотите поддержать 3.3+, да, я думаю, что это отличное решение.

До 3.3 использование пакета для плагинов было намного более проблематичным. Люди придумали множество различных систем плагинов - в одном случае, вплоть до динамического создания объектов модуля и execfile. Если вам нужно это решить, я бы предложил посмотреть существующие приложения Python с плагинами (например, MusicBrainz Picard), чтобы получить разные идеи.

+0

Спасибо за пример! Я действительно не мог понять, как работал importlib. – gcq