简体   繁体   English

美丽的for循环嵌套在dict函数中:这是如何工作的?

[英]beautiful for loop nested in the dict function : how does that work?

I am currently reviewing this post about a sudoku solver in Python. 我目前正在回顾这篇关于Python中的数独求解器的帖子 I am trying to deconstruct it line by line, and I went through the following 我试图逐行解构它,我经历了以下几点

digits   = '123456789'
rows     = 'ABCDEFGHI'
cols     = digits
#squares will give you all the squares of a Sudoku, from A1-A9 to I1-I9
squares  = cross(rows, cols)
unitlist = ([cross(rows, c) for c in cols] +
            [cross(r, cols) for r in rows] +
            [cross(rs, cs) for rs in ('ABC','DEF','GHI') for cs in ('123','456','789')])

#each square has 3 units : the row it is in, the column it is in, and the "block" of 3x3 squares it is in :

units = dict((s, [u for u in unitlist if s in u]) 
             for s in squares)

That last part is what dumbfounds me. 最后一部分让我感到茫然。 We have, if I am not mistaken, a list comprehension, inside a generator. 如果我没有弄错的话,我们有一个列表理解,在发电机内部。 But what is the "for s in squares" doing inside the dict function ? 但是在dict函数中做什么是“for s in square”? How comes I can't write the following and obtain the same result ? 为什么我不能写下面的内容并获得相同的结果?

for s in squares :
    units3 = dict((s, [u for u in unitlist if s in u]))

This seems pretty obsure to me, unfortunately all my attempts at finding a ressource for this end up with results that point to basic tutorials on dict creation, or looping over dict values... 这对我来说似乎非常模糊,不幸的是我所有尝试为此找到一个资源的结果都指向了有关dict创建的基本教程或循环dict值的结果......

Could you please either tell me how a for loop inside a dict function works, or point me towards a good tuto on that topic ? 你能不能告诉我dict函数中的for循环是如何工作的,还是指向一个关于该主题的好tuto?

It's not a list comprehension, but a generator expression. 它不是列表理解,而是生成器表达式。 The two are related, but no list is built. 这两者是相关的,但没有建立列表。 A generator expression produces a generator object, something that can be iterated over lazily and each step the loop expression is executed. 生成器表达式生成一个生成器对象,可以在懒惰的情况下迭代,并且每一步都执行循环表达式。

For example, you could create such an expression to calculate squares: 例如,您可以创建这样的表达式来计算方块:

>>> squares = (i ** 2 for i in range(10))
>>> squares
<generator object <genexpr> at 0x10c832468>
>>> next(squares)
0
>>> next(squares)
1
>>> next(squares)
4

The next() function advances the iterator to produce the next value. next()函数使迭代器前进以产生下一个值。 In between, the generator is paused, the remaining values have yet to be computed. 在两者之间,生成器暂停,剩余的值尚未计算。

In the example you found, the generator expression is the only argument to the dict() call, in which case the (...) for the generator expression can be omitted. 在您找到的示例中,生成器表达式是dict()调用的唯一参数,在这种情况下,可以省略生成器表达式的(...) You could also write dict((...)) and it'll produce the exact same results; 你也可以写dict((...)) ,它会产生完全相同的结果; if a call takes more than one argument those parentheses would be required instead. 如果一个调用需要多个参数,那么将需要这些括号。 Nested inside the dict(...) generator expression is a list comprehension for just the dictionary value. 嵌套在dict(...)生成器表达式中只是字典值的列表解析。

The generator produces (key, value) tuples, which the dict() callable uses to create a dictionary. 生成器生成(key, value)元组, dict() callable用它来创建字典。 See the dict() documentation : 请参阅dict()文档

[...] Otherwise, the positional argument must be an iterable object. [...]否则,位置参数必须是可迭代对象。 Each item in the iterable must itself be an iterable with exactly two objects. iterable中的每个项目本身都必须是具有两个对象的可迭代项。 The first object of each item becomes a key in the new dictionary, and the second object the corresponding value. 每个项目的第一个对象成为新词典中的一个键,第二个对象成为相应的值。

So the equivalent for loop statement would be: 因此,相当于for循环语句应该是:

units = {}
for s in squares:
    units[s] = [u for u in unitlist if s in u]

Note the [u for u in unitlist if s in u] list comprehension; 注意[u for u in unitlist if s in u] list comprehension; it is a separate expression independent from the generator expression (but it does use the current value of s each time). 它是一个独立于生成器表达式的独立表达式(但它每次都使用s的当前值)。 The loop sets a value in a dictionary we had to create up front here, but otherwise each iterable step has the same outcome: a key s is set with the list comprehension result as the value. 循环在我们必须在此处创建的字典中设置一个值,但是否则每个可迭代步骤具有相同的结果:使用列表推导结果作为值设置键s

In Python 2.7 and Python 3, instead of a generator expression, you can use a dictionary comprehension to produce the exact same dictionary: 在Python 2.7和Python 3中,您可以使用字典理解来生成完全相同的字典,而不是生成器表达式:

units = {s: [u for u in unitlist if s in u] for s in squares}

The pattern for a dictionary comprehension is {<key expression>: <value expression> for ... in ... <optionally more if filters and for loops>} ; 字典理解的模式是{<key expression>: <value expression> for ... in ... <optionally more if filters and for loops>} ; compare this to the dict((<key expression>, <value expression>) for ... in ... <optionally more if filters and for loops>) pattern used by the code you found. 将其与dict((<key expression>, <value expression>) for ... in ... <optionally more if filters and for loops>)模式使用您找到的代码。 A dictionary comprehension is faster, because the interpreter no longer has to worry about how to stop and start a generator expression each step, nor does it have to locate the dict name and call out to it. 字典理解更快,因为解释器不再需要担心如何在每一步停止和启动生成器表达式,也不必定位dict名称并调用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM