Python 神奇的扁平化方法是如何工作的?

Python 神奇的扁平化方法是如何工作的?,python,Python,我正在读“开始python,从新手到专业人士”,其中有一个神奇的扁平化函数,这让我很困惑 def flatten(nested): try: for sublist in nested: for element in flatten(sublist): yield element except TypeError: yield nested 我知道收益率返回一个元素。假设我得到了一个列表L=

我正在读“开始python,从新手到专业人士”,其中有一个神奇的扁平化函数,这让我很困惑

def flatten(nested):
    try:
        for sublist in nested:
            for element in flatten(sublist):
                yield element
    except TypeError:
        yield nested
我知道收益率返回一个元素。假设我得到了一个列表
L=[1,[[2]]]
。 我用这个flatte()来称呼它,比如:


我真的很困惑,当我们调用for循环时,我们是否会触发flatte(),并且我们看到第一个元素
1
,这无疑会导致try块中的
TypeError
,except块中返回的
嵌套的
变量不应该是整个列表
[1,[[2]]
?为什么它会返回
1

也许不使用
yield
重写函数可以让您更容易理解:

def flatten(nested):
    res = []
    try:
        for sublist in nested:
            for element in flatten(sublist):
                res.append(element)
    except TypeError:
        res.append(nested)
    return res

从最基本的角度来说,这就是
收益率的作用。它从函数一次“发送”一个值。有关更完整的解释,请参见的答案。

插入打印语句以查看发生了什么可能会有所帮助。例如

#! /usr/bin/env python

def flatten(nested, depth=0):
    print "%d: %r" % (depth, nested)
    try:
        for sublist in nested:
            for element in flatten(sublist, depth+1):
                yield element
    except TypeError:
        yield nested


def main():
    L = [ 1, [[2]] ]
    for i in flatten(L):
        print "output %s\n" % i


if __name__ == '__main__':
    main()
输出

0: [1, [[2]]]
1: 1
output 1

1: [[2]]
2: [2]
3: 2
output 2

我想我现在明白这里发生了什么

def flatten(nested):
    try:
        for sublist in nested:
            for element in flatten(sublist):
                yield element
    except TypeError:
        yield nested
我们仍然有
L=[1,[[2]]]
,我们称之为
flatten(L)

现在第一个元素是1,现在我们已经移动到flatte(1)
中元素的

当我们调用flatte()并遇到TypeError时,我们将得到
nested
变量,在这里,它是1

所以我们得到了
1

原来的L现在只剩下
[[2]]

正如我们在flatte(L)
中为i调用for循环:
,事情将继续进行

现在我们将移动到扁平化([[2]])中的元素的
,是的,我们在它下面得到了一个
屈服元素
,但是我们必须首先对扁平化([[2]])中的元素执行
,然后看看发生了什么

现在我们将转到flatte([2])
中的
元素,直接转到它下面的
屈服元素。但是,等一下,我们下次再去找平

现在我们要移动到展平(2)
,它将像展平(1)一样引发TypeError

所以这次我们得到了
2


事情解释清楚了

yield
不是
return
。另请参见此函数合并和。这两个概念似乎让很多程序员感到困惑。不要将此函数用于包含字符串的列表,否则会得到无限递归(因为字符串是可写的,它们的元素也是字符串)。
def flatten(nested):
    try:
        for sublist in nested:
            for element in flatten(sublist):
                yield element
    except TypeError:
        yield nested