Создание минимальной сменной архитектуры в Python

Поскольку Google Translate API закрывается как бесплатный сервис, вы можете попробовать эту бесплатную альтернативу, заменяющую Google Translate API:

http://detectlanguage.com

182
задан dF. 31 May 2009 в 02:46
поделиться

7 ответов

Мой, по сути, каталог с названием «плагины», который основное приложение может опрашивать, а затем использовать imp.load_module для получения файлов, ищите хорошо известный точка входа, возможно, с параметрами конфигурации на уровне модуля, и перейти оттуда. Я использую средства мониторинга файлов для определенной степени динамизма, при котором плагины активны, но это полезно иметь.

Конечно, любое возникающее требование говорит: «Мне не нужна [большая, сложная вещь ] X; Я просто хочу что-то легкое "рискует повторно реализовать X одно обнаруженное требование за раз. Но это не значит, что вы все равно не можете повеселиться :)

145
ответ дан 23 November 2019 в 06:05
поделиться

Мне понравилось обсуждение различных архитектур плагинов, проведенное доктором Андре Робержем на Pycon 2009. Он дает хороший обзор различных способов реализации плагинов, начиная с чего-то действительно простого.

Его доступен в виде подкаста (вторая часть после объяснения обезьяньего исправления), сопровождаемого серией из шести записей в блоге .

Я рекомендую быстро прослушать его, прежде чем делать решение.

7
ответ дан 23 November 2019 в 06:05
поделиться

Я биолог на пенсии, который занимался цифровыми микрографами и обнаружил, что ему нужно написать пакет обработки и анализа изображений (технически не библиотеку) для работы на машине SGi. Я написал код на C и использовал Tcl в качестве языка сценариев. Графический интерфейс в том виде, в каком он был, был выполнен с использованием Tk. Команды, появившиеся в Tcl, имели форму «extensionName commandName arg0 arg1 ... param0 param1 ...», то есть простые слова и числа, разделенные пробелами. Когда Tcl увидел подстроку extensionName, управление было передано пакету C. Это, в свою очередь, запустило команду через лексический анализатор / анализатор (выполненное в lex / yacc), а затем при необходимости вызвало подпрограммы C.

Команды для работы с пакетом могут запускаться одну за другой через окно в графическом интерфейсе пользователя, но пакетные задания выполнялись путем редактирования текстовых файлов, которые были действительными сценариями Tcl; вы должны выбрать шаблон, который выполняет нужную вам операцию на уровне файла, а затем отредактировать копию, чтобы она содержала фактические имена каталогов и файлов, а также команды пакета. Оно работало завораживающе. Пока ...

1) Мир превратился в ПК и 2) сценарии стали длиннее примерно 500 строк, когда сомнительные организационные возможности Tcl начали превращаться в настоящее неудобство. Прошло время ...

Я ушел на пенсию, был изобретен Python, и он выглядел как идеальный преемник Tcl. Я никогда не делал перенос, потому что я никогда не сталкивался с проблемами компиляции (довольно больших) программ C на ПК, расширения Python с помощью пакета C и создания графического интерфейса пользователя в Python / Gt? / Tk? /? ? Однако старая идея редактируемых шаблонных скриптов все еще работает. Также, ввод команд пакета в нативной форме Python не должен быть слишком большой проблемой, например:

packageName.command (arg0, arg1, ..., param0, param1, ...)

Несколько дополнительных точек , скобки и запятые, но это не остановка.

Я помню, как видел, что кто-то сделал версии lex и yacc на Python (попробуйте: http://www.dabeaz.com/ply/ ]), так что, если они все еще нужны, они есть.

Суть этой бессвязной беседы в том, что мне показалось, что сам Python ЯВЛЯЕТСЯ желаемым «легким» интерфейсом, который могут использовать ученые. Мне любопытно узнать, почему вы думаете, что это не так, и я серьезно об этом говорю.


добавлено позже: приложение gedit ожидает добавления плагинов, и на их сайте есть наиболее четкое объяснение простого плагин процедура I ' Я нашел за несколько минут, осмотревшись. Попробуйте:

https://wiki.gnome.org/Apps/Gedit/PythonPluginHowToOld

Я все же хотел бы лучше понять ваш вопрос. Мне неясно, 1) хотите ли вы, чтобы ученые могли довольно просто использовать ваше (Python) приложение различными способами, или 2) хотите, чтобы ученые могли добавлять новые возможности в ваше приложение. Выбор №1 - это ситуация, с которой мы столкнулись с изображениями, и которая заставила нас использовать общие сценарии, которые мы изменили в соответствии с потребностями момента. Является ли выбор №2, который приводит вас к идее плагинов, или это какой-то аспект вашего приложения, который делает невозможным выполнение команд для него?

Мне неясно, 1) хотите ли вы, чтобы ученые могли довольно просто использовать ваше (Python) приложение различными способами, или 2) хотите, чтобы ученые могли добавлять новые возможности в ваше приложение. Выбор №1 - это ситуация, с которой мы столкнулись с изображениями, и которая заставила нас использовать общие сценарии, которые мы изменили в соответствии с потребностями момента. Является ли выбор №2, который приводит вас к идее плагинов, или это какой-то аспект вашего приложения, который делает невозможным выполнение команд для него?

Мне неясно, 1) хотите ли вы, чтобы ученые могли довольно просто использовать ваше (Python) приложение различными способами, или 2) хотите, чтобы ученые могли добавлять новые возможности в ваше приложение. Выбор №1 - это ситуация, с которой мы столкнулись с изображениями, и которая заставила нас использовать общие сценарии, которые мы изменили в соответствии с потребностями момента. Является ли выбор №2, который приводит вас к идее плагинов, или это какой-то аспект вашего приложения, который делает невозможным выполнение команд для него?

11
ответ дан 23 November 2019 в 06:05
поделиться

Взгляните на в этом обзоре существующих фреймворков / библиотек плагинов , это хорошая отправная точка. Мне очень нравится yapsy , но это зависит от вашего варианта использования.

30
ответ дан 23 November 2019 в 06:05
поделиться

Хотя этот вопрос действительно интересен, я думаю, что на него довольно сложно ответить без дополнительных подробностей. Что это за приложение? У него есть графический интерфейс? Это инструмент командной строки? Набор скриптов? Программа с уникальной точкой входа и т. Д.

Учитывая небольшой объем информации, который у меня есть, я отвечу в очень общей форме.

Какие средства вы должны добавлять плагины?

  • Вам, вероятно, придется добавить файл конфигурации, в котором будут перечислены пути / каталоги для загрузки.
  • Другой способ - сказать «все файлы в этом подключаемом модуле / каталоге будут загружены», но при этом неудобно требовать от пользователей перемещаться по файлам.
  • Последний промежуточный вариант - потребовать все подключаемые модули находиться в том же плагине / папке, а затем активировать / деактивировать их, используя относительные пути в файле конфигурации.

На чистом уровне кода / дизайна вам нужно будет четко определить, какое поведение / конкретные действия вы хотите, чтобы ваши пользователи расширили. Определите общую точку входа / набор функций, которые всегда будут игнорироваться, и определите группы в рамках этих действий. Как только это будет сделано, вы сможете легко расширить ваше приложение,

Пример с использованием хуков , вдохновленный MediaWiki (PHP, но действительно ли язык имеет значение?):

import hooks

# In your core code, on key points, you allow user to run actions:
def compute(...):
    try:
        hooks.runHook(hooks.registered.beforeCompute)
    except hooks.hookException:
        print('Error while executing plugin')

    # [compute main code] ...

    try:
        hooks.runHook(hooks.registered.afterCompute)
    except hooks.hookException:
        print('Error while executing plugin')

# The idea is to insert possibilities for users to extend the behavior 
# where it matters.
# If you need to, pass context parameters to runHook. Remember that
# runHook can be defined as a runHook(*args, **kwargs) function, not
# requiring you to define a common interface for *all* hooks. Quite flexible :)

# --------------------

# And in the plugin code:
# [...] plugin magic
def doStuff():
    # ....
# and register the functionalities in hooks

# doStuff will be called at the end of each core.compute() call
hooks.registered.afterCompute.append(doStuff)

Другой пример, вдохновленный Mercurial . Здесь расширения только добавляют команды к исполняемому файлу командной строки hg , расширяя поведение.

def doStuff(ui, repo, *args, **kwargs):
    # when called, a extension function always receives:
    # * an ui object (user interface, prints, warnings, etc)
    # * a repository object (main object from which most operations are doable)
    # * command-line arguments that were not used by the core program

    doMoreMagicStuff()
    obj = maybeCreateSomeObjects()

# each extension defines a commands dictionary in the main extension file
commands = { 'newcommand': doStuff }

Для обоих подходов вам могут потребоваться общие initialize и finalize для вашего расширение. Определите общую точку входа / набор функций, которые всегда будут игнорироваться, и определите группы в рамках этих действий. Как только это будет сделано, вы сможете легко расширить ваше приложение,

Пример с использованием хуков , вдохновленный MediaWiki (PHP, но действительно ли язык имеет значение?):

import hooks

# In your core code, on key points, you allow user to run actions:
def compute(...):
    try:
        hooks.runHook(hooks.registered.beforeCompute)
    except hooks.hookException:
        print('Error while executing plugin')

    # [compute main code] ...

    try:
        hooks.runHook(hooks.registered.afterCompute)
    except hooks.hookException:
        print('Error while executing plugin')

# The idea is to insert possibilities for users to extend the behavior 
# where it matters.
# If you need to, pass context parameters to runHook. Remember that
# runHook can be defined as a runHook(*args, **kwargs) function, not
# requiring you to define a common interface for *all* hooks. Quite flexible :)

# --------------------

# And in the plugin code:
# [...] plugin magic
def doStuff():
    # ....
# and register the functionalities in hooks

# doStuff will be called at the end of each core.compute() call
hooks.registered.afterCompute.append(doStuff)

Другой пример, вдохновленный Mercurial . Здесь расширения только добавляют команды к исполняемому файлу командной строки hg , расширяя поведение.

def doStuff(ui, repo, *args, **kwargs):
    # when called, a extension function always receives:
    # * an ui object (user interface, prints, warnings, etc)
    # * a repository object (main object from which most operations are doable)
    # * command-line arguments that were not used by the core program

    doMoreMagicStuff()
    obj = maybeCreateSomeObjects()

# each extension defines a commands dictionary in the main extension file
commands = { 'newcommand': doStuff }

Для обоих подходов вам могут потребоваться общие initialize и finalize для вашего расширение. Определите общую точку входа / набор функций, которые всегда будут игнорироваться, и определите группы в рамках этих действий. Как только это будет сделано, вы сможете легко расширить ваше приложение,

Пример с использованием хуков , вдохновленный MediaWiki (PHP, но действительно ли язык имеет значение?):

import hooks

# In your core code, on key points, you allow user to run actions:
def compute(...):
    try:
        hooks.runHook(hooks.registered.beforeCompute)
    except hooks.hookException:
        print('Error while executing plugin')

    # [compute main code] ...

    try:
        hooks.runHook(hooks.registered.afterCompute)
    except hooks.hookException:
        print('Error while executing plugin')

# The idea is to insert possibilities for users to extend the behavior 
# where it matters.
# If you need to, pass context parameters to runHook. Remember that
# runHook can be defined as a runHook(*args, **kwargs) function, not
# requiring you to define a common interface for *all* hooks. Quite flexible :)

# --------------------

# And in the plugin code:
# [...] plugin magic
def doStuff():
    # ....
# and register the functionalities in hooks

# doStuff will be called at the end of each core.compute() call
hooks.registered.afterCompute.append(doStuff)

Другой пример, вдохновленный Mercurial . Здесь расширения только добавляют команды к исполняемому файлу командной строки hg , расширяя поведение.

def doStuff(ui, repo, *args, **kwargs):
    # when called, a extension function always receives:
    # * an ui object (user interface, prints, warnings, etc)
    # * a repository object (main object from which most operations are doable)
    # * command-line arguments that were not used by the core program

    doMoreMagicStuff()
    obj = maybeCreateSomeObjects()

# each extension defines a commands dictionary in the main extension file
commands = { 'newcommand': doStuff }

Для обоих подходов вам могут потребоваться общие initialize и finalize для вашего расширение. но действительно ли язык имеет значение?):

import hooks

# In your core code, on key points, you allow user to run actions:
def compute(...):
    try:
        hooks.runHook(hooks.registered.beforeCompute)
    except hooks.hookException:
        print('Error while executing plugin')

    # [compute main code] ...

    try:
        hooks.runHook(hooks.registered.afterCompute)
    except hooks.hookException:
        print('Error while executing plugin')

# The idea is to insert possibilities for users to extend the behavior 
# where it matters.
# If you need to, pass context parameters to runHook. Remember that
# runHook can be defined as a runHook(*args, **kwargs) function, not
# requiring you to define a common interface for *all* hooks. Quite flexible :)

# --------------------

# And in the plugin code:
# [...] plugin magic
def doStuff():
    # ....
# and register the functionalities in hooks

# doStuff will be called at the end of each core.compute() call
hooks.registered.afterCompute.append(doStuff)

Другой пример, вдохновленный Mercurial. Здесь расширения только добавляют команды к исполняемому файлу командной строки hg , расширяя поведение.

def doStuff(ui, repo, *args, **kwargs):
    # when called, a extension function always receives:
    # * an ui object (user interface, prints, warnings, etc)
    # * a repository object (main object from which most operations are doable)
    # * command-line arguments that were not used by the core program

    doMoreMagicStuff()
    obj = maybeCreateSomeObjects()

# each extension defines a commands dictionary in the main extension file
commands = { 'newcommand': doStuff }

Для обоих подходов вам могут потребоваться общие initialize и finalize для вашего расширение. но действительно ли язык имеет значение?):

import hooks

# In your core code, on key points, you allow user to run actions:
def compute(...):
    try:
        hooks.runHook(hooks.registered.beforeCompute)
    except hooks.hookException:
        print('Error while executing plugin')

    # [compute main code] ...

    try:
        hooks.runHook(hooks.registered.afterCompute)
    except hooks.hookException:
        print('Error while executing plugin')

# The idea is to insert possibilities for users to extend the behavior 
# where it matters.
# If you need to, pass context parameters to runHook. Remember that
# runHook can be defined as a runHook(*args, **kwargs) function, not
# requiring you to define a common interface for *all* hooks. Quite flexible :)

# --------------------

# And in the plugin code:
# [...] plugin magic
def doStuff():
    # ....
# and register the functionalities in hooks

# doStuff will be called at the end of each core.compute() call
hooks.registered.afterCompute.append(doStuff)

Другой пример, вдохновленный Mercurial. Здесь расширения только добавляют команды к исполняемому файлу командной строки hg , расширяя поведение.

def doStuff(ui, repo, *args, **kwargs):
    # when called, a extension function always receives:
    # * an ui object (user interface, prints, warnings, etc)
    # * a repository object (main object from which most operations are doable)
    # * command-line arguments that were not used by the core program

    doMoreMagicStuff()
    obj = maybeCreateSomeObjects()

# each extension defines a commands dictionary in the main extension file
commands = { 'newcommand': doStuff }

Для обоих подходов вам могут потребоваться общие initialize и finalize для вашего расширение. You can either use a common interface that all your extension will have to implement (fits better with second approach; mercurial uses a reposetup(ui, repo) that is called for all extension), or use a hook-kind of approach, with a hooks.setup hook.

But again, if you want more useful answers, you'll have to narrow down your question ;)

25
ответ дан 23 November 2019 в 06:05
поделиться

module_example.py :

def plugin_main(*args, **kwargs):
    print args, kwargs

loader.py :

def load_plugin(name):
    mod = __import__("module_%s" % name)
    return mod

def call_plugin(name, *args, **kwargs):
    plugin = load_plugin(name)
    plugin.plugin_main(*args, **kwargs)

call_plugin("example", 1234)

Это определенно «минимально», в нем нет абсолютно никакой проверки ошибок, возможно, бесчисленные проблемы с безопасностью, это не так. очень гибкий - но он должен показать вам, насколько простой может быть система плагинов в Python.

Возможно, вы захотите также изучить модуль imp , хотя вы можете многое сделать с помощью всего лишь __import __ , os.listdir и некоторые манипуляции со строками.

53
ответ дан 23 November 2019 в 06:05
поделиться

Простая структура плагинов Марти Алчина - это база, которую я использую для своих нужд. Я действительно рекомендую взглянуть на него, я думаю, что это действительно хорошее начало, если вы хотите что-то простое и легко взломанное. Вы также можете найти его как фрагменты кода Django .

11
ответ дан 23 November 2019 в 06:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: