2011-07-21 60 views
11

我想編寫一個接受路徑作爲字符串或文件對象的函數。到目前爲止,我有:接受文件對象或路徑的Python函數

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) 

其中do_stuff需要一個打開的文件對象。

有沒有更好的方法來做到這一點? 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

不應該'產量'是'產量f'? –

+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

啊,是啊,對不起。我只是把它改爲'awesome_parse',以免與'super'混淆。 – TorelTwiddler

+0

好吧,我會編輯我的配對。 – agf

+1

看起來好像你的回答落入了@Ned Batchelder的回答地址(提前關閉文件)的陷阱。我確實喜歡裝飾者的想法,所以我也會使用你的想法! – TorelTwiddler