遇到字符串时的递归生成器

时间:2018-01-28 06:56:32

标签: python python-3.x recursion generator

这是我的代码:

def flatten(nested):
    try:
        for sublist in nested:
            for element in flatten(sublist):
                yield element
    except TypeError:
        yield nested

这是一本书中的例子,该书由Magus Lie Hetland撰写,名为Beginning Python From Novice to Professional。

它说,如果这个列表中有一个字符串,它将通过递归无穷无尽。 是的,这是真的。但是,如果我使用这台发电机,我该怎么办?我是一个新学习者。谢谢你的教学。最后,我的英语很差,如果你努力阅读,我很抱歉。我会尽力改进。

3 个答案:

答案 0 :(得分:2)

在字符串的情况下会发生无限递归,因为它是可迭代的

你的函数依赖于TypeError来打破递归,所以这里代码通常是如何进行的:

> flatten([[1,2],[3,4]])     ---function call
> for e in ([[1,2],[3,4]])   ---outer loop
> for i in flatten([1,2])    ---inner loop
> for e in ([1,2])           ---recursion outer loop
> for i in flatten(1)        ---recursion inner loop
> for e in 1 [TYPE_ERROR]    ---recursion2 outer loop
> yield 1                    ---recursion2 except call
> etc...

正如您所看到的,当程序尝试迭代整数(1)时,会发生TypeError,导致函数无法递归。但是,这不会发生在字符串中:

> flatten([["hi","hello"],[3,4]])     ---function call
> for e in ([["hi","hello"],[3,4]])   ---outer loop
> for i in flatten(["hi","hello"])    ---inner loop
> for e in (["hi","hello"])           ---recursion outer loop
> for i in flatten("hi")              ---recursion inner loop
> for e in "hi"                       ---recursion2 outer loop
> for i in flatten("h")               ---recursion2 inner loop
> for e in "h"                        ---recursion3 outer loop
> for i in flatten("h")               ---recursion3 inner loop
> and so on forever

因为python仍会迭代单个字符串,并且该函数依赖于类型异常来停止递归,所以该函数将无限期地运行(好吧,直到达到最大递归深度并且程序至少崩溃)。

因此,如果你想将这个函数用于字符串,你只需要创建一个条件来检查函数是否在字符串上迭代:

def flatten(nested):
    try:
        if isinstance(nested, str):
                yield nested
        else:        
            for sublist in nested:
                for element in flatten(sublist):
                    yield element
    except TypeError:
        yield nested 

使用添加的if语句,您应该能够使用字符串:

mylist = [["hi","hello"],[3,4]]

for e in flatten(mylist):
    print(e)

---Output---

hi
hello
3
4

答案 1 :(得分:0)

我认为@avghdev通过检查str而不是检查list犯了一个大错误 - list是我们想要重复出现的积极情况。在所有其他情况下,我们希望产生普通值

下面,我们使用yield from委托给另一台生成器。在这种情况下,我们的flatten生成器是递归的,因为它会自行生成。

由于这项实施,该计划将消除痛苦和痛苦。

def flatten (xs):
  for x in xs:
    if isinstance (x, list):
      yield from flatten (x)
    else:
      yield x

for x in flatten ([ 1, [ '2', [ 3, [ '4', [ 5, None ]]]]]):
  print (x)

# 1
# 2
# 3
# 4
# 5
# None

答案 2 :(得分:0)

好的,我找到了解决办法:

 def flatten(nested):
    try:
        if isinstance(nested, str):
            for i in nested:
                yield i
        else:
            for sublist in nested:
                for element in flatten(sublist):
                    yield element
    except TypeError:
        yield nested


lista = [[1, 2], 3, ['abc',[1, 'abc']]]
for i in flatten(lista):
    print(i)
----Output----
1
2
3
a
b
c
1
a
b
c