Стратегии сценариев Python: выполнение сценария дважды против исключения - PullRequest
1 голос
/ 02 марта 2012

Я пишу скрипт, который получает два списка данных и ищет различия, чтобы обновить данные в базе данных.Эти списки неоднородны: один представляет собой список объектов базы данных, другой представляет собой список словарей.По многим причинам этот инструмент предлагает возможность предварительного просмотра списка различий перед применением изменений.После анализа предварительного просмотра, если обновление принято модератором, изменения будут применены.Это означает, что скрипт, содержащий множество циклов и условных тестов, сгенерирует список предварительного просмотра (подается на выходную страницу) и список изменений.

На первом этапе разработки я написал один скрипт, который будет работать в двух режимах: «Предварительный просмотр» и «Обновление».Этот сценарий выполнял все циклы и условные проверки, и если в какой-то момент были найдены изменения, он добавил бы сообщение к выходной строке, если выполнялся в режиме «предварительного просмотра», или выполнил команду, если работал в режиме «обновления».

Тогда я начал думать, что, возможно, было бы лучше проходить между циклами и условными проверками только один раз, добавляя сообщения предварительного просмотра к выходной строке и команды в список команд всякий раз, когда обнаруживается изменение.

Затем, после отправки страницы предварительного просмотра модератору, если изменения будут приняты, запустите второй скрипт, который будет таким простым:

def apply_changes(command_list, ...):
    for c in command_list:
        try:
            exec(c)
        except Exception, err:
            logger.error('Something went wrong while executing command %s: %s', c, err)
            raise Exception, err

Q: Будетбудет нормально переключиться на вторую версию скрипта?Какие предостережения / ошибки / странное поведение будут связаны?

Я задавал почти такой же вопрос под тегом, не зависящим от языка ,потому что меня больше интересовала алгоритмическая точка зрения на проблему, чем ее реализация.

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

Есть ли причины, по которым я бы предпочел первую версию?

РЕДАКТИРОВАТЬ: Добавление некоторого кода, чтобы прояснить вопрос еще больше.

Выдержка из кода первой версии будет что-то вроде этой функции (используется в более простом возможном случае, в которомсравниваемые значения - это строки), вызываемые другими функциями внутри вложенного цикла for, если выполняются некоторые конкретные условия:

def update_text_field(object, old_value, new_value, field_name, mode):
    ....
    if old_value != new_value:
        if mode is 'preview': output += print_old_new_values(old_value, new_value, field_name)
        if mode is 'update':
           if hasattr(object, field_name):
            setattr(object, field_name, new_value)
            object.save()
           else:
            ... 
         ....

Во второй версии этот отрывок будет преобразован в нечто вроде этого:

def update_text_field(object, old_value, new_value, field_name, mode):
    ....
    if old_value != new_value:
        output_list.append(print_old_new_values(old_value, new_value, field_name))
        command_list.append(generate_command(command, old_value, new_value, field_name))
    ...

1 Ответ

1 голос
/ 02 марта 2012

Одной из причин, по которой вы предпочитаете первую версию, является возможность запуска сценария только в режиме update (пропуская обязательный шаг в сценарии preview шаг).

Вотпредложение о том, как сделать скрипт проще в обслуживании: абстрагироваться от режима, когда скрипт работает.Это можно сделать следующим образом:

def generate_diff(f, other parameters...):
    # ... Do computations ...
    # Whenever command "c" needs to be previewed/executed, do:
    f(c)
    # ... More computations...

И затем вы можете определить оба режима (это просто упрощенный пример):

def _previewMode(command):
    print command

def _updateMode(command):
    exec(command)

И опционально определить вспомогательные оболочки:

def preview(other parameters...):
    return generate_diff(_previewMode, other parameters...)

def update(other parameters...):
    return generate_diff(_updateMode, other parameters...)

И даже легко определить новые режимы:

def _interactiveMode(command):
    if raw_input('Execute command ' + command + '?').lower() in ('yes', 'y'):
        print 'Command returned:', exec(command)

def interactive(other parameters...):
    return generate_diff(_interactiveMode, other parameters...)

Это возможно благодаря первоклассным функциям в Python .Таким образом, единственные вещи, которые вам нужно поддерживать, очень четко разделены, и не нужно заботиться друг о друге :

  • Сценарий diff
  • Чточто делать с командой в режиме preview
  • Что делать с командой в режиме update

Нет дублирующейся версии функции, нет, возможно, дорого-в долгосрочной перспективе ветвление внутри функции diff, простое в обслуживании.

Если не важно иметь возможность работать в режиме update напрямую, не проходя через preview, то лучшийПараметр производительности действительно позволяет создать список команд в режиме preview, а затем запустить его в режиме update.Его так же легко обслуживать, как и вышеупомянутое решение.Однако, даже если вы выберете эту опцию, подумайте, насколько легко было бы реализовать этот шаблон:

def buildCommandList(other parameters...):
    commandList = []
    generate_diff(commandList.append, other parameters...)
    return commandList
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...