Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python脚本策略:运行脚本两次vs EXEC_Python_Performance_Algorithm - Fatal编程技术网

Python脚本策略:运行脚本两次vs EXEC

Python脚本策略:运行脚本两次vs EXEC,python,performance,algorithm,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
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))
    ...
def generate_diff(f, other parameters...):
    # ... Do computations ...
    # Whenever command "c" needs to be previewed/executed, do:
    f(c)
    # ... More computations...

选择第一个版本的一个原因是,您可以仅在
update
模式下运行脚本(跳过第二个脚本
preview
步骤中的必填项)

关于如何使脚本更易于维护,这里有一个建议:在脚本运行时抽象掉模式。可以这样做:

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))
    ...
def generate_diff(f, other parameters...):
    # ... Do computations ...
    # Whenever command "c" needs to be previewed/executed, do:
    f(c)
    # ... More computations...
然后您可以定义两种模式(这只是一个简单的示例):

并可选择定义便利包装:

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...)
这是可能的,因为。这样,您只需要将需要维护的东西非常干净地分开,并且不必相互关心

  • 差异脚本
  • 预览
    模式下如何处理命令
  • 更新
    模式下如何处理命令
该函数没有重复版本,从长远来看,diff函数内部的分支可能不昂贵,易于维护

如果能够在
更新
模式下直接运行而不经过
预览
并不重要,那么最好的性能选项确实是在
预览
模式下构建一个命令列表,然后在
更新
模式下运行它。它与上述解决方案一样易于维护。但是,即使你真的选择这个选项,也要考虑使用上面的模式:
def buildCommandList(other parameters...):
    commandList = []
    generate_diff(commandList.append, other parameters...)
    return commandList

选择第一个版本的一个原因是,您可以仅在
update
模式下运行脚本(跳过第二个脚本
preview
步骤中的必填项)

关于如何使脚本更易于维护,这里有一个建议:在脚本运行时抽象掉模式。可以这样做:

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))
    ...
def generate_diff(f, other parameters...):
    # ... Do computations ...
    # Whenever command "c" needs to be previewed/executed, do:
    f(c)
    # ... More computations...
然后您可以定义两种模式(这只是一个简单的示例):

并可选择定义便利包装:

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...)
这是可能的,因为。这样,您只需要将需要维护的东西非常干净地分开,并且不必相互关心

  • 差异脚本
  • 预览
    模式下如何处理命令
  • 更新
    模式下如何处理命令
该函数没有重复版本,从长远来看,diff函数内部的分支可能不昂贵,易于维护

如果能够在
更新
模式下直接运行而不经过
预览
并不重要,那么最好的性能选项确实是在
预览
模式下构建一个命令列表,然后在
更新
模式下运行它。它与上述解决方案一样易于维护。但是,即使你真的选择这个选项,也要考虑使用上面的模式:
def buildCommandList(other parameters...):
    commandList = []
    generate_diff(commandList.append, other parameters...)
    return commandList

如果您可以钩住更改,为什么不构建更改队列而不是python命令列表?命令列表从何而来?
exec
看起来像是一个潜在的安全漏洞,通过您可以定义的某种apply函数可以很容易地避免它。@wim:是从脚本本身生成的(为了清晰起见,将添加一些代码)@Odomontois:请您详细说明一下“构造更改队列”好吗?您真的不应该将Python代码作为字符串生成。。。如果你把对局部变量的引用也放在里面,它就不起作用了。相反,您应该存储闭包或元组
(函数、args列表、关键字args字典)