列表理解循环顺序取决于嵌套

Tad*_*sen 5 python list-comprehension dictionary-comprehension

如果可能的话,我正在寻找对嵌套数据结构使用推导式的替代方法,或使用嵌套列表推导式的方法。

在没有理解的情况下,使用嵌套循环生成项目列表的工作方式如下:

combos = []
for a in iterable:
    for b in valid_posibilities(a):
        combos.append((a,b))
Run Code Online (Sandbox Code Playgroud)

将其转换为理解保留了循环的顺序,这使得使用多行很好:

combos = [
    (a,b)
    for a in iterable
        for b in valid_posibilities(a)
    ]
Run Code Online (Sandbox Code Playgroud)

但是,这会创建一个列表。如果我想要一些代码来生成嵌套数据结构,那么我会使用这样的东西:

# same as above but instead of list of (a,b) tuples,
# I want a dictionary of {a:[b]} structure
combos_map = {}
for a in iterable:
    options = []
    for b in valid_posibilities(a):
        options.append(b)
    combos_map[a] = options
Run Code Online (Sandbox Code Playgroud)

(以下代码段具有使用普通列表的等效代码,适用于那些之前没有看过字典理解并且第一次看到它以奇怪的方式嵌套的人很难理解)

combos = []
for a in iterable:
    for b in valid_posibilities(a):
        combos.append((a,b))
Run Code Online (Sandbox Code Playgroud)

现在将其转换为理解,我们得到:

combos_map = {
    a:[b
        for b in valid_posibilities(a)
      ]
    for a in iterable
    }
Run Code Online (Sandbox Code Playgroud)

有没有搞错?循环的顺序切换了!这是因为内部循环必须放在内部列表中。如果在您想要嵌套数据结构时总是反转它,我会很好,但条件或非嵌套循环会使情况变得更糟:

# for a list of files produce a mapping of {filename:(set of all words)}
# only in text files.
file_to_words_map = {}
for filename in list_of_files:
    if filename.endswith(".txt"):
        word_set = set()
        for line in open(filename):
            for word in line.split():
                word_set.add(word)
        file_to_words_map[filename] = word_set
        

### or using comprehension we get this lovely mess:

file_to_words_map = {
    filename: { word
            for line in open(filename)
               for word in line.split()
        }
    for filename in list_of_files
        if filename.endswith(".txt")
    }
Run Code Online (Sandbox Code Playgroud)

我向初学者教授 Python,在有人想要生成带有理解的嵌套数据结构的情况下,我告诉他们“这不值得”,我希望能够将它们发送到这里作为对原因的更好解释。

因此,对于我将派往这里的人,我正在寻找以下人员之一:

  1. 有没有另一种方法来重构这些类型的循环,使代码更容易理解,而不是直接将它们粘贴在推导式中?

  2. 有没有办法以直观的方式解释和构造这些嵌套循环?在某些时候,不熟悉 python 推导式的人会偶然发现一些像这里显示的代码,希望最终会在这里寻找一些见解。

ypn*_*nos 5

也许问题在于您过度使用列表理解。我也喜欢它,但是,当代码变得比循环更复杂时,它有什么用途?

如果您想继续使用列表理解高于一切的方法,您可以将内部循环分解为辅助函数。这样更容易消化:

def collect_words(file):
    ...

file_to_words_map = {
    filename: collect_words(open(filename))
    for filename in list_of_files if filename.endswith(".txt")
}
Run Code Online (Sandbox Code Playgroud)

顺便说一句,我认为将这些语句分成多行并不一定会使它们更清晰(相反,您这样做的冲动很有说服力)。在上面的例子中,我故意重新加入了forif部分。

  • +1000 列表推导式旨在成为创建列表的简洁方式。不要成为另一种循环。 (3认同)