每当您将该方法作为生成器调用时(例如for x in get_reverse_iterator()),python 就会开始逐行执行该方法。每当它碰到yield 时,它就会停止冷却并返回它。当它在for 循环的下一次迭代中被要求提供next() 值时,它会继续执行。
这看起来像是一个相当简单的链表遍历习语,其中列表的每个元素都包含本身就是一个列表的数据(或其他一些可迭代的值,如字符串):
list[0].data = [1, 2, 3, 4]
list[1].data = [5, 6, 7, 8]
...
list[9].data = [37, 38, 39, 40]
所以代码在 here 所做的是将这些子列表从主列表的后面打印到主列表的前面。输出应如下所示:
37 38 39 40 33 34 35 36 ... 5 6 7 8 [1, 2, 3, 4]
当您查看代码的执行方式时,这一点变得显而易见。我会用文字重写它:
func get_reverse_iterator(head) {
if head isn't the last element of the list, then
call this function on the next element of the list (head.next)
for every element in the return value of that,
yield that element
yield this element's data
“基本情况”是列表的最后一个元素,没有.next。所以它的data,它是可迭代的,被返回到倒数第二个元素。倒数第二个元素依次生成该数据的每个元素,然后将其自己的数据返回给倒数第三个元素。倒数第三个元素依次产生该数据的每个元素,依此类推,直到最终到达列表的第一个元素。到目前为止,每条yield 语句都递归地向上传递了一个元素,因此第一个元素的内部for 循环到目前为止已经产生了36 个值。最后,列表中所有后面的元素都完成了传递值,因此第一个元素到达函数的最后一条语句并产生自己的数据。
但是没有什么可以捕获产生的数据并按单个元素解析它,因此它首先打印为list。或者,至少,对于我上面介绍的示例而言。
在您的情况下,它更简单,因为当您遍历 string 时,每个项目仍然是 string。但在较小的范围内也是如此:
-
在
lst的根节点上调用get_reverse_iterator()
- 根节点(我称之为
NodeA)有一个.next
-
在下一个节点上调用
get_reverse_iterator(),我将调用它NodeB
-
NodeB 有一个.next
-
在下一个节点上调用
get_reverse_iterator(),我将调用它NodeC
-
NodeC 没有 .next
-
get_reverse_iterator(NodeC) 跳过for 循环并产生NodeC.data,即'c'`
-
get_reverse_iterator(NodeB) 在 for 循环内捕获 'c' 并生成它
-
get_reverse_iterator(NodeA) 在 for 循环内捕获 'c' 并生成它
-
'c' 被分配给x,并被打印出来。
- 外循环的下一次迭代发生,执行返回
get_reverse_iterator(NodeB)
-
for 循环结束,因为 get_reverse_iterator(NodeC) 已停止产生东西
-
get_reverse_iterator(NodeB) 结束for 循环,退出if 块,最后产生NodeB.data,即'b'
-
get_reverse_iterator(NodeA) 在 for 循环中捕获 'b' 并产生它
-
'b' 被分配给 x,并被打印出来。
- 外循环的下一次迭代发生,执行返回
get_reverse_iterator(NodeA)
-
for 循环结束,因为 get_reverse_iterator(NodeC) 已停止产生东西
-
get_reverse_iterator(NodeA) 结束for 循环,退出if 块,最后产生NodeA.data,即'a'
-
'a' 被分配给 x,并被打印出来
- 外部
for 循环结束,因为get_reverse_iterator(NodeA) 已停止产生东西。