2012-03-23 34 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

相關問題