用更好的代码替代两个for循环

15
我有两个for循环,我想用列表推导式、lambda或其他方法使它更好。如何实现相同的功能?
例如:
filename = ['a.txt', 'b.txt', 'c.txt']
for files in filename:
    for f in glob.glob(os.path.join(source_path, files)):
        print f
        ... some processing...

我建议首先确保你真的需要那个。例如,Google Python风格指南建议你的代码已经很好了(这里有一个关于列表推导的部分,lambda函数在下面)。 - Anton Strogonoff
4个回答

27

你的代码已经很好,如果引入不必要的复杂结构反而会降低其可读性。


@thebjom:你能解释一下哪些不必要的复杂结构吗? - sam
2
列表解析和Lambda表达式都不能提高代码的清晰度,因此它们只会增加复杂性。当然,在某些情况下,它们可以使事情更清晰,但这不是其中之一。 - thebjorn
3
+1. 而且,Pythonic等同于英语。有时你别无选择,只能使用2、3甚至4层嵌套的循环来编写,因为很难使用推导式或lambda表达式。而且,如果代码风格有问题,调试和编写文档可能会花费很长时间。 - CppLearner
4
@CppLearner 我不同意使用4个嵌套循环,通常情况下,如果你发现自己需要4个嵌套循环,那么引入一个函数并进行重构是一个好的选择。然而,在这种情况下使用2个嵌套循环似乎完全没有问题。 - amit

4
你可以将这两个for循环压缩成一个单独的生成器表达式,并使用新的for循环从中提取文件名。
for f in (f_ for files in filename
             for f_ in glob.glob(os.path.join(source_path, files))):
    print f
    # ...

作为另一位回答所说,这不是更好的选择,而是更糟糕的选择,你不应该使用它(我不确定这是否已经强调得足够了!)。它要难理解许多,并且可能性能上并没有太大的优势(实际上,额外的间接层意味着它很可能会更慢)。
(* 在基本等价于列表推导式的情况下,但在像这样的情况下更好。)

4
我会像下面这样做。原因是现在你可以将搜索模式的形成、搜索和文件处理分开。如果它们没有关联,那么扩展起来就更容易。
如果你的系统有些奇特(例如分布式网络驱动器),同时使用glob和os.path.join的代码行可能会很难看。尽管其他人已经提到了,但两个循环也完全没问题。
filename = ['a.txt', 'b.txt', 'c.txt']

searchPatterns = [os.path.join(source_path, files) for files in filename]

searchResults = [glob.glob(pattern) for pattern in searchPatterns]

fileListFlat = sum(searchResults,[])

for file in fileListFlat:
    print file

2
长表达式很难阅读,尤其是当你不得不向右扫描并返回时。如果在几行中有许多本地变量、lambda和comprehension,并且仅由括号和逗号分隔,则情况会更糟。只有在代码不变得更长和更复杂的情况下才使用它们。
对于您的情况,我更倾向于以牺牲find为代价。但正如顶部答案所说,您的代码已经足够好了。
from itertools import chain

find = lambda p: glob.glob(os.path.join(source_path, p))
for file in chain(map(find, filename)):
    """
    =) I like one-level indentation here.
    =( I don't know which file pattern is used currently,
       unless I use longer expression...
    """

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接