4.14 展开嵌套的�列¶

问题¶

你想将一个多层嵌套的�列展开�一个�层列表

解决方案¶

�以写一个包� yield from 语�的递归生�器�轻�解决这个问题。比如:

from collections import Iterable

def flatten(items, ignore_types=(str, bytes)):
    for x in items:
        if isinstance(x, Iterable) and not isinstance(x, ignore_types):
            yield from flatten(x)
        else:
            yield x

items = [1, 2, [3, 4, [5, 6], 7], 8]
# Produces 1 2 3 4 5 6 7 8
for x in flatten(items):
    print(x)

在上�代�中, isinstance(x, Iterable) 检查�个元素是�是�迭代的。 如果是的�, yield from 就会返回所有�例程的值。最终返回结果就是一个没有嵌套的简��列了。

�外的�数 ignore_types 和检测语� isinstance(x, ignore_types) 用�将字符串和字节排除在�迭代对象外,防止将它们�展开��个的字符。 这样的�字符串数组就能最终返回我们所期望的结果了。比如:

>>> items = ['Dave', 'Paula', ['Thomas', 'Lewis']]
>>> for x in flatten(items):
...     print(x)
...
Dave
Paula
Thomas
Lewis
>>>

讨论¶

语� yield from 在你想在生�器中调用其他生�器作为�例程的时候�常有用。 如果你�使用它的�,那么就必须写�外的 for 循环了。比如:

def flatten(items, ignore_types=(str, bytes)):
    for x in items:
        if isinstance(x, Iterable) and not isinstance(x, ignore_types):
            for i in flatten(x):
                yield i
        else:
            yield x

尽管�改了一点点,但是 yield from 语�看上去感觉更好,并且也使得代�更简�清爽。

之��到的对于字符串和字节的�外检查是为了防止将它们�展开��个字符。 如果还有其他你�想展开的类型,修改�数 ignore_types ��。

最��注�的一点是, yield from 在涉�到基于�程和生�器的并�编程中扮演�更加��的角色。 �以�考12.12�节查看�外一个例�。