【问题标题】:Conditionally writing to different output files有条件地写入不同的输出文件
【发布时间】:2014-09-16 07:56:35
【问题描述】:

我有可自定义的脚本,可以根据请求提供多达 3 个不同的输出文件。目前我有:

with open("option1", "w") as file1, open("option2", "w") as file2, open("option3", "w") as file3:

我遇到的问题是,如果未选择该选项,文件仍在创建中(因为 open 语句),这是我想避免的。

天真地,我认为我想要的是一种允许的语法,类似于以下允许的行:

with (if type1: open("option1", "w") as file1), (if type2: open("option2", "w") as file2), (if type3: open("option3", "w") as file3): 

这 3 种不同的类型和对应的选项并不相互排斥,通常需要 1 种以上的文件类型。 type1、type2 和 type3 变量是布尔值,默认设置为 False,并在命令行中独立切换为 True。总的来说,我试图有效地避免创建空文件,并且愿意对代码进行相当大的更改来完成它。

【问题讨论】:

    标签: python if-statement with-statement


    【解决方案1】:

    一次可以有多个类型吗?如果没有,我会在写入文件之前设置一个条件,如下所示:

    if type1:
        fname = "option1"
    elif type2:
        fname = "option2"
    elif type3:
        fname = "option3"
    
    with open(fname, "w") as outfile:
        outfile.write("ok!")
    

    【讨论】:

    • 这3种类型并不互斥。有人可能想要所有 3 种类型的任意组合,通常选项 2 和 3 一起选择,但不是必须的。
    【解决方案2】:

    我会在你打开文件之前弄清楚文件。

    if type1:
        filename = "option1"
    elif type2:
        filename = "option2"
    elif type3:
        filename = "option3"
    
    with open(filename, 'w') as outfile:
        #do stuff
    

    【讨论】:

    • 这3种类型并不互斥。换句话说,有人可能想要所有 3 种类型的任意组合。
    【解决方案3】:
    filenames_map = {"type1":"option1", "type2":"option2", "type3":"option3"}
    filename = filenames_map.get(type, "default_option")
    with open(filname, "w") as targetFile:
        # do whatever needs to be done
    

    dict.get 从字典中获取值,默认为 no such key found 的第二个参数。

    如果类型不是互斥的,那就有点棘手了。 with 是复合语句,所以在正常执行流程下(无异常),这两者大致等价:

    with (context_manager) as something:
        do_stuff()  
    
    try:
        context_manager.__enter__()
        do_stuff()
    finally:
        context_manager.__exit__()
    

    因此,如果您在运行前无法确定要写入的文件数量,则您必须自己管理上下文。幸运的是,open 返回FileObject,这是定义了__enter____exit__ 的上下文管理器。幸运的是,open 返回FileObject,这是一个非常简单的上下文管理器。如documentation中所述

    with open("hello.txt") as f:
        for line in f:
            print line,
    

    等于

    f = open("hello.txt")
    try:
        for line in f:
            print line,
    finally:
        f.close()
    

    现在,重点

    target_files = []
    # please modify to follow PEP-8 yourself, compressed for clarity
    if user_wants_type1(type): target_files.append("option1")
    if user_wants_type2(type): target_files.append("option2")
    if user_wants_type3(type): target_files.append("option3")
    
    try:
        handles = [open(filename) for filename in taget_files]
        for handle in handles:
            handle.write("something")
    finally:
        for handle in handles:
            handle.close()
    

    【讨论】:

    • 我正在尝试对此进行一些测试,但似乎只能写入单个文件? type1、type2 和 type3 也是不同的变量,默认情况下为 False,在命令行中设置为 True,而不是单个变量设置为指定值。将更新问题以反映其中的一些内容
    • @ded 更新为允许写入多个文件。为了使用type1type2type3 作为不同的变量,只需将if user_wants_typeN(type): ... 替换为if typeN: ...
    • 这很好,但仍然有些限制,因为每个句柄都是单独打开的,所以我必须为 3 个句柄中的每一个单步执行相同的“某事”。我会对此提出任何建议,但我将倾向于重新设计“某物”,以便将其分类为 3 种不同的类型。
    【解决方案4】:

    如果你使用 Python3,你可以使用contextlib.ExitStack:

    import contextlib
    filenames = ['option{}'.format(i) for i in range(1,4)]
    types = [type1, type2, type3]
    
    with contextlib.ExitStack() as stack:
        files = [stack.enter_context(open(filename, 'w'))
                 for filename, typ in zip(filenames, types) if typ]
    

    对于 Python2,您可以使用 contextlib2 module

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-04-09
      • 2012-07-13
      • 1970-01-01
      • 2022-11-17
      • 2016-01-27
      • 2019-04-04
      • 2014-08-28
      相关资源
      最近更新 更多