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å°�节查看å�¦å¤–一个例å�。