2011-07-21 6 views
11

パスを文字列またはファイルオブジェクトとして受け入れる関数を記述したいと思います。これまでのところ私が持っている:ファイルオブジェクトまたはパスを受け入れるPython関数

do_stuffが開かれたファイルオブジェクトを受け取り
def awesome_parse(path_or_file): 
    if isinstance(path_or_file, basestring): 
     f = open(path_or_file, 'rb') 
    else: 
     f = path_or_file 
    with f as f: 
     return do_stuff(f) 

これを行うより良い方法はありますか? with f as f:には何らかの反響がありますか?

ありがとうございます!

答えて

14

あなたのコードに関して奇妙なことは、開いているファイルが渡された場合、それを閉じることです。これは良くありません。ファイルを開いたコードが何であれ、ファイルを閉じる責任があります。

def awesome_parse(path_or_file): 
    if isinstance(path_or_file, basestring): 
     f = file_to_close = open(path_or_file, 'rb') 
    else: 
     f = path_or_file 
     file_to_close = None 
    try: 
     return do_stuff(f) 
    finally: 
     if file_to_close: 
      file_to_close.close() 

することはでき独自のコンテキストマネージャ書き込むことによって、この抽象化:これは、しかし、もう少し複雑な関数を作る

@contextlib.contextmanager 
def awesome_open(path_or_file): 
    if isinstance(path_or_file, basestring): 
     f = file_to_close = open(path_or_file, 'rb') 
    else: 
     f = path_or_file 
     file_to_close = None 

    try: 
     yield f 
    finally: 
     if file_to_close: 
      file_to_close.close() 

def awesome_parse(path_or_file): 
    with awesome_open(path_or_file) as f: 
     return do_stuff(f) 
+0

ああ...いいえファイルを閉じるときにそれを閉じてはいけません!私は間違いなくそれが起こることを望んでいません。ありがとう! – TorelTwiddler

+1

「yield f」を「yield」してはいけませんか? –

+0

'@ contextlib.contextmanager'は正確に何をしますか?私はなぜそれなしで 'AttributeError:__exit__'を取得するのですか?ありがとう! –

3

あなたは行うことができます:

def awesome_parse(do_stuff): 
    """Decorator to open a filename passed to a function 
     that requires an open file object""" 
    def parse_path_or_file(path_or_file): 
     """Use a ternary expression to either open the file from the filename 
      or just pass the extant file object on through""" 
     with (open(path_or_file, 'rb') 
       if isinstance(path_or_file, basestring) 
       else path_or_file) as f: 
      return do_stuff(f) 
    return parse_path_or_file 

そして、あなたが開いているファイルオブジェクト上のものを行う任意の関数を宣言します。

@awesome_parse 
def do_things(open_file_object): 
    """This will always get an open file object even if passed a string""" 
    pass 

@awesome_parse 
def do_stuff(open_file_object): 
    """So will this""" 
    pass 

編集2:デコレータに関するより詳細な情報を。

+0

ああ、ええ、申し訳ありません。私は 'super 'と混同しないように' awesome_parse'に変更しました。 – TorelTwiddler

+0

ええ、私は一致するように編集します。 – agf

+1

@Ned Batchelderの回答アドレスと同じトラップに回答があるかのように見えます(ファイルを途中で閉じる)。私はしかし、デコレータのアイデアのように、私はあなたのアイデアを少しでも使用しています! – TorelTwiddler

関連する問題