2014-06-08 76 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

相关问题