我正在玩Python中的生成器,我正在尝试使用简单的递归方案来实现flatten-function 。也就是说,一个函数将一个可能包含子列表的列表作为输入,并输出一个只能在输入的原子元素上迭代的可迭代对象。
因此,print(list(flatten([1,2,3,[4,5,6]])))
应返回包含[1,2,3,4,5,6]
的内容。
我的尝试如下:
def flatten(toflatten):
try:
for element in toflatten:
flatten(element)
except TypeError:
yield toflatten
因此,它应该检查其参数是否是可迭代对象。如果是这种情况,也递归此对象。否则,将其作为原子元素。
这不起作用,flatten([1,2,3,[4,5,6]])
只返回一个空列表。
为什么会这样?特别是;为什么它甚至没有对此输入执行递归函数调用? (我使用的是Python 3.5)
答案 0 :(得分:5)
所以,你正试图压扁一个列表。你已走上正轨,但你犯了几个错误。他们在这里。
将您的try-except
移到循环中。使用您的代码,如果为一个元素引发TypeError
,则循环停止运行。你不希望发生这种情况。
在尝试中,你什么都没有。只进行函数调用。你也应该从那里归还一些东西。如果您有python3.3 +,我建议yield from
。
最后,在except
中,您需要yield element
,而不是toflatten
。不要产生整个清单。
def flatten(toflatten):
for element in toflatten:
try:
yield from flatten(element)
except TypeError:
yield element
这给了,
>>> list(flatten([1,2,3,[4,5,6]]))
[1, 2, 3, 4, 5, 6]
您已经使用了EAFP(比请求更容易请求宽恕),这很不错。这是实现目标的一种方式(实际上是我最喜欢的),但有一个缺点:这会在字符串上崩溃。
还有另一种方法:LYBL(在你跳跃之前看)。它包括更谨慎,使用if
语句,因此不会引发错误。
def flatten(toflatten):
for element in toflatten:
if isinstance(element, list):
yield from flatten(element)
else:
yield element
其作用与以前相同,并给出,
>>> list(flatten([1,2,3,[4,5,6]]))
[1, 2, 3, 4, 5, 6]
然而,这是有利的,因为仅在子列表上调用yield from
生成器委托。我是否提到它也适用于字符串元素?
>>> list(flatten([1,2,3,[4,5,'abc']]))
[1, 2, 3, 4, 5, 'abc']
注意,在任何一种情况下,如果你有递归定义的列表,那么无限递归的警告。例如,flatten
将因此类输入而崩溃。
x = [1, 2, 3]
x.append(x)
flatten(x)
您最终会收到运行时错误:
RuntimeError: maximum recursion depth exceeded