Python 脚本策略 : running script twice vs excec

标签 python performance algorithm

我正在编写一个脚本,它接收两个数据列表并查找差异,以便将数据更新到数据库中。
这些列表是非同类的:一个是数据库对象列表,另一个是字典列表。
出于多种原因,此工具提供了在应用更改之前预览差异列表的机会。
分析预览后,如果版主接受更新,将应用更改。

这意味着包含大量循环和条件测试的脚本将生成预览列表(提供给输出页面)和更改列表。


在开发的第一阶段,我编写了一个脚本,该脚本将以两种模式运行:“预览”和“更新”。
该脚本执行所有循环和条件检查,如果在某个时刻发现更改,如果在“预览”模式下运行,它将向输出字符串添加一条消息,或者如果在“更新”模式下运行,则执行一条命令。

然后我开始考虑在循环和条件检查之间只传递一次可能会更好,每当发现更改时,将预览消息添加到输出字符串并将命令添加到命令列表。

然后,在向版主提供预览页面后,如果更改被接受,则运行第二个脚本,这很简单:

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

问:可以切换到第二版脚本吗?会涉及哪些警告/错误/奇怪的行为?


我一直在问almost the same question under the language-agnostic tag ,
因为我对问题的算法观点比对其实现更感兴趣。

但是更多地关注实现的观点,似乎使用 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))
    ...

最佳答案

您更喜欢第一个版本的一个原因是能够仅在 update 模式下运行脚本(跳过 mandatory-in-second-script 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...)

这是可能的,因为 first-class functions in Python .这样一来,您唯一需要维护的东西就完全分开了,不必关心彼此:

  • 差异脚本
  • preview 模式下如何处理命令
  • update 模式下如何处理命令

函数没有重复版本,diff 函数内部没有可能在长期运行中产生昂贵的分支,维护起来非常容易。

如果能够不经过preview直接以update模式运行并不重要,那么最好的性能选择确实是在preview 模式,然后在 update 模式下运行。它与上述解决方案一样易于维护。然而,即使您选择了这个选项,也要考虑使用上述模式实现起来有多么容易:

def buildCommandList(other parameters...):
    commandList = []
    generate_diff(commandList.append, other parameters...)
    return commandList

关于Python 脚本策略 : running script twice vs excec,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9526238/

相关文章:

.net - 队列 <T> 与列表 <T>

javascript - 过滤一次或过滤多次

python - 根据条件pandas python随机选择行

python类变量按值查找

python - 为什么计算路径大小的结果与使用 du 计算相同路径的结果不同

php - 确定数据中的连胜

performance - jackson 和 gson 之间的 json 解析性能

python - 无法弄清楚为什么我的代码不适用于特定情况(Leetcode 的硬币找零)

java - 找到最长的递减序列

python - 程序的输出与公式不匹配(概率问题)