2014-06-08 75 views
0

我有一個目錄列表。在這個列表中,我想查找帶有特定文件的第一個目錄並返回該文件的abspath。我目前有以下代碼可以工作:在目錄列表中找到文件的第一個出現

from os.path import exists, join, abspath 

path = ["/some/where", "/some/where/else", "/another/location"] 
file_name = "foo.bar" 
try: 
    file = [abspath(join(d, file_name)) for d in path if exists(join(d, file_name))][0] 
except IndexError: 
    file = "" 

我該如何做到這一點更優雅?我特別不喜歡這兩個連接。

回答

1

你可以拉join出到genexp:

>>> paths = ["/some/where", "/some/where/else", "/another/location", "/tmp"] 
>>> file_name = "foo.bar" 
>>> joined = (join(p, file_name) for p in paths) 
>>> next((abspath(f) for f in joined if exists(f)), '') 
'/tmp/foo.bar' 

(你可以平凡使這個如果通過內聯它想一個班輪。)

注意,這不同於你的代碼因爲它在找到第一個之後就停止了,而你的代碼找到了它們。

+0

內聯以供參考:'下((ABSPATH(F)對於f在(合併(P,FILE_NAME),用於在路徑P)是否存在(F)), '')' – jorgen

0

即使你的文件名加入目錄前手避免參加兩次,你還在加入所有目錄。例如,如果列表中有10個目錄,即使包含該文件的目錄可能在列表中處於第一位,您也會調用os.path.join() 10次。更糟糕的是,當你需要做數千次或數百萬次時,它就會加起來。

我看不到使用列表理解的優雅解決方案,所以我設計了一個迭代的解決方案。在我的解決方案中,只要找到包含該文件的目錄,我們立即將完整的絕對路徑返回給該文件,不再進行處理。這個解決方案不夠優雅,但速度更快。

該解決方案的缺點是調用函數的開銷。如果您發現列表的末尾,我的解決方案可能會比列表理解解決方案慢。

import os 

def find_first(directories, filename): 
    ''' 
    Given a list of directories and a file name, find first existent 
    occurrence. 
    ''' 
    for directory in directories: 
     fullpath = os.path.abspath(os.path.join(directory, filename)) 
     if os.path.exists(fullpath): 
      return fullpath 
    return False 

directories = ['/foo', '/bin', '/usr/bin'] 
filename = 'bash' 
print find_first(directories, filename) # /bin/bash 
+0

這是排序標準的10行代碼,我正在尋求一個優雅的解決方案。但是,這是可讀的,單線版本不是。 – jorgen

相關問題