2012-03-23 54 views
4

我有一个脚本接受作为参数的文件名,而不是打开它并写入一些东西。如果没有提供文件名回退到标准输出

我使用with声明:

with open(file_name, 'w') as out_file: 
    ... 
    out_file.write(...) 

现在,如果我想如果没有提供file_namesys.stdout

我是否需要将一个函数中的所有动作都包装起来,并在之前放置一个条件?

if file_name is None: 
    do_everything(sys.stdout) 
else: 
    with open(file_name, 'w') as out_file: 
     do_everything(out_file) 

回答

6
from contextlib import contextmanager 
@contextmanager 
def file_or_stdout(file_name): 
    if file_name is None: 
     yield sys.stdout 
    else: 
     with open(file_name, 'w') as out_file: 
      yield out_file 

然后,你可以做

with file_or_stdout(file_name) as wfile: 
    do_stuff_writing_to(wfile) 
+0

这似乎很多pythonic :)需要一些'import'我猜 – neurino 2012-03-23 09:29:19

+0

是的,对不起。只需以我喜欢的方式添加'import'语句。随意使用它,不用'as'或'from'。 – glglgl 2012-03-23 09:37:52

0
if file_name is None: 
    fd = sys.stdout 
else: 
    fd = open(file_name, 'w') 

# write to fd 

if fd != sys.stdout: 
    fd.close(); 
2

你可以编写自己的上下文管理。如果没有其他人,我会在以后发布示例代码

+0

好的,但不会是我的解决方法更容易阅读和理解?无论如何,这是一个很好的观点+1。 – neurino 2012-03-23 09:19:34

0

使用with ... as构造对于自动关闭文件非常有用。这意味着,使用它与sys.stdout,我猜你知道,将崩溃您的程序,因为它会尝试关闭系统标准输出!

这意味着像with open(name, 'w') if name else sys.stdout as:不会工作。

这让我说没有任何简单的好方法来更好地编写代码片段......但是可能有更好的方法来思考如何构建这样的代码!

要澄清的主要问题是当file_name存在时需要打开(并且更重要的是关闭)file_name的文件处理程序。

就我个人而言,我会简单地删除with .. as并照顾打开文件 - 更重要的是关闭它! - 别的地方。里程可能会有所不同,这取决于您的软件的工作方式。

这意味着你可以简单地做:

out_file = open(file_name, 'w') if file_name else sys.stdout 

,并与整个程序out_file工作。

当您关闭,记得要检查它是否是一个文件或不:)

而且你有没有想过干脆使用logging模块?这很容易让你添加不同的处理程序,打印到文件,打印到stdout ...

+0

感谢提示,但我正在使用python模块 – neurino 2012-03-23 09:17:38

+0

@neurino写一个'csv',其余答案仍然适用。其实即使使用日志记录仍然会工作;-)可能它可能是矫枉过正! – Stefano 2012-03-23 09:19:31

+0

@neurino和wrt你对@paxdiablo的评论回答,请仔细阅读我写的内容:你真的不能在'sys.stdout'上使用'with',因为你不希望它被关闭!这会让你的python程序崩溃! – Stefano 2012-03-23 09:21:17

3

你是如何处理的命令行参数?如果您使用​​,则可以使用add_argument的参数typedefault来处理此问题。例如,你可以试试下面的:

import sys 
import argparse 

def main(argv=None): 

    if argv is None: 
     argv=sys.argv[1:] 

    parser = argparse.ArgumentParser() 

    parser.add_argument('infile', nargs='?', 
     type=argparse.FileType('w'), 
     default=sys.stdin) 

    args = parser.parse_args(argv) 

    print args.infile 

    return 0 

if __name__=="__main__": 
    sys.exit(main(sys.argv[1:])) 

如果文件名存在作为参数的脚本argparse会自动打开和关闭该文件,并args.infile将是一个句柄到这个文件。否则args.infile将只是sys.stdin

+0

不错,不知道'argparse.FileType' + 1会照顾关闭文件吗? PS你可以避免所有这些sys.argc [1:] ... :) – neurino 2012-03-23 09:54:19

+0

是的,你可以。 'sys.argv [1:]'仅用于从参数列表中删除脚本名称,这通常是您想要执行的操作。 – Chris 2012-03-23 09:57:53

+0

'args = parser.parse_args()'通常是我所要做的;) – neurino 2012-03-23 10:08:07

相关问题