过滤包含其他列表中任何项目的任何部分的任何内容的列表

时间:2016-03-18 20:28:39

标签: python python-2.7 lambda

我想缩短这个功能:

def get_filenames(path, banned_files=() ):
    file_list = []
    for root, _, files in os.walk(path):
        BANNED_FILES = banned_files
        for f in files:
            for string in BANNED_FILES:
                if string in f:
                    continue
            path = os.path.join(root, f)
            file_list.append(path)
    return file_list

用作:

filenames = get_filenames(CLIENT_TESTS_PATH, banned_files=['__init__.py', '.pyc', 'accounts.py, otherfile.py'])

这样来自CLIENT_TESTS_PATH的任何文件都没有任何禁止的文件。我不能只检查文件路径是否在列表理解的禁止文件中,因为我关心是否可以在客户端文件中的任何位置找到任何禁止的文件。如何有效地使用过滤器,列表推导和/或lambda来缩短它?我只想要那个目录中的文件,而不是它下面的dirs。 谢谢

对于

def get_files(path, banned_files=[]):
    return [os.path.join(root, fname) for root, _, fnames in os.path.walk(path) for fname in fnames \
                if not any(bad_fname in fname for bad_fname in banned_files)]

我得到了

In [2]: CLIENT_TESTS_PATH = "/home/cchilders/work_projects/webapi"    

In [3]: get_files(CLIENT_TESTS_PATH)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-3c5a75968d68> in <module>()
----> 1 get_files(CLIENT_TESTS_PATH)

/home/cchilders/scripts/my_scripting_library/sysadmin.py in get_files(path, banned_files)
     15 
     16 def get_files(path, banned_files=[]):
---> 17     return [os.path.join(root, fname) for root, _, fnames in os.path.walk(path) for fname in fnames \
     18                 if not any(bad_fname in fname for bad_fname in banned_files)]
     19 

TypeError: walk() takes exactly 3 arguments (1 given)

6 个答案:

答案 0 :(得分:1)

类似的东西:

banned_files=['__init__.py', '.pyc', 'accounts.py', 'otherfile.py']
file_list = ["""Some list of files here"""] 
new_list = {file_name for file_name in file_list for bf in banned_files if bf not in file_name}

这将过滤掉文件名中包含这些字符串的任何内容。这意味着"my_accounts.py.txt"之类的东西会被阻止。将它们分开可能更好。例如:

banned_files=['__init__.py', 'accounts.py', 'otherfile.py']
banned_extensions = ['.pyc']
new_list = {file_name for file_name in file_list for ext in banned_extensions if file_name not in banned_files and not file_name.endswith(ext)}

编辑以包含os.walk ......一秒钟。

答案 1 :(得分:1)

列表理解:

def get_filenames(path, banned_files=()):
    return [os.path.join(root, f) for root,_,files in os.walk(path) for f in files]

这与您发布的代码的功能相同,但它可能不会执行您想要的操作。你的for string in BANNED_FILES:循环完全没用,因为它所做的只是继续,但continue只在当前循环中起作用;它不会影响for f in files:循环,因此除了浪费处理时间之外,内循环绝对没有任何作用。要做我认为你想要的事情,请执行以下操作:

def get_filenames(path, banned_files=()):
    return [os.path.join(root, f) 
            for root,_,files in os.walk(path)
                for f in files
                    if not any(string in f for string in banned_files)
    ]

答案 2 :(得分:1)

[os.path.join(root, fname) for root, _, fnames in os.path.walk(path) for fname in fnames \
    if not any(bad_fname in fname for bad_fname in banned)]

答案 3 :(得分:1)

试试这个:

def get_filenames(path, banned_files=()):
    file_list = [os.path.join(root, f) for root, _, files in os.walk(path)
                 for f in files if all(s not in f for s in banned_files)]
    return file_list

答案 4 :(得分:0)

列表理解是IMHO最清晰的方式:

[os.path.join(root, f) for root, _, files in os.walk(path) \
for f in files  if all([bf not in f for bf in banned_files])]

不要忘记all()中的括号:

In [7]: [f for f in ['abc','def','ghi','jkl']   if all([bf not in f \
for bf in ['a','e','z']])]
Out[7]: ['ghi', 'jkl']

In [8]: [f for f in ['abc','def','ghi','jkl']   if all(bf not in f \
for bf in ['a','e','z'])]
Out[8]: ['abc', 'def', 'ghi', 'jkl']

答案 5 :(得分:0)

我会这样做:

def get_filenames(path, banned_files=[]):
    banned = '|'.join(banned_files)
    return [os.path.join(root, f)
            for root, _, files in os.walk(path)
            for f in files
            if f not in banned]

说明:

|不能在文件名中使用,因此我们可以将其用作包含所有禁止文件的字符串的分隔符。检查找到的单个字符串的文件名要快得多。