【发布时间】:2021-02-20 22:32:08
【问题描述】:
如果可能,我正在寻找对嵌套数据结构使用推导式的替代方法,或者寻找适应嵌套列表推导式的方法。
如果没有理解,使用嵌套循环生成项目列表的工作方式如下:
combos = []
for a in iterable:
for b in valid_posibilities(a):
combos.append((a,b))
把它变成一个理解保留了循环的顺序,这使得使用多行很好:
combos = [
(a,b)
for a in iterable
for b in valid_posibilities(a)
]
但是,这会创建一个列表。如果我想要一些代码来生成嵌套数据结构,那么我会使用这样的东西:
# 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
(以下 sn-p 具有使用普通列表的等效代码,对于那些以前没有看过字典理解的人来说,第一次看到它以一种奇怪的方式嵌套很难理解)
# for people unfamilar with dictionary comprehension
# this is the equivelent nesting structure
combos = []
for a in iterable:
options = []
for b in valid_posibilities(a):
options.append(b)
combos.append(options)
######## or equivelently
combos = [
[b
for b in valid_posibilities(a)
]
for a in iterable
]
现在将其转换为推导式,我们得到:
combos_map = {
a:[b
for b in valid_posibilities(a)
]
for a in iterable
}
什么鬼?循环的顺序切换了!这是因为必须将内部循环放在内部列表中。如果当你想要一个嵌套数据结构时它总是被颠倒我会很好,但条件或非嵌套循环会使它变得更糟:
# 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")
}
我向初学者教授 Python,当有人想要生成带有理解的嵌套数据结构时,我告诉他们“这不值得”,我希望能够将它们发送到这里作为更好的解释为什么。
因此,对于我将发送到这里的人,我正在寻找的是以下之一:
-
是否有另一种方法可以重构这些循环,使代码更容易理解,而不是直接将它们粘贴在推导式中?
-
有没有办法以直观的方式解释和构造这些嵌套循环? 有时,不熟悉 python 理解的人会偶然发现一些像这里显示的代码,希望会最后在这里寻找一些见解。
【问题讨论】:
-
让 Python 奇怪的是,当多个
for子句出现在一个理解的同一级别时,外部循环首先出现。这与通常将它们分组的方式相反,第一个循环是内部分组的一部分。 Fortran 有隐含的 DO 循环,它们使用了更合乎逻辑的顺序。为方便起见,Python 将其颠倒过来,但它使其不太一致且更加混乱。 -
@MichaelButscher 这通常出现在有人使用列表推导但希望使其生成嵌套数据结构时,我不可避免地告诉他们只使用显式循环,他们问为什么。总是很难平衡挥手或过多的细节来给出一个令人满意的答案,说明为什么它不值得。我真正的目标是“查找这个答案”作为解释:)
-
@TadhgMcDonald-Jensen - 问题以“我正在寻找一种有助于记住和轻松解析列表理解的直觉”开头。问题以放弃最初的问题结束,而是说“所以我真正的问题是:有没有另一种方法来重构这些循环,使代码更容易理解,而不是直接将它们粘贴在理解中?”。这不是大转弯,大矛盾吗?未来的读者会对这里的真正问题感到困惑。它还会引起关于已发布答案的相关性的可避免的辩论。
-
@fountainhead 谢谢并已修复。我开始尝试模仿 this question in intent,但在收到 cmets 关于“不要进行嵌套推导,因为它们令人困惑”之后意识到那是错误的方向,所以我改写了它,错过了开头的句子。
-
@TadhgMcDonald-Jensen - 就我个人而言,现在已删除的原始问题是更有趣的问题(实际上已经开始着手回答它了!)。我真的不相信嵌套循环有一些需要重构的固有不可读性。 AFAIK,人们使用推导式最流行的动机是潜在的简洁性,而不是因为嵌套循环有一些不可读性
标签: python list-comprehension dictionary-comprehension