收益率与收益率的结果不同

时间:2010-01-10 14:27:29

标签: python recursion yield

我真的不明白yield语句在这种情况下是如何工作的。问题是,给定一个没有括号的表达式,编写一个函数来生成所有可能的完全括号(FP)表达式。比如,输入是'1+2+3+4',应该生成5个FP表达式:

  1. (1+(2 +(3 + 4)))
  2. (1 +((2 + 3)4))
  3. ((1 + 2)+(3 + 4))
  4. ((1+(2 + 3))+ 4)
  5. (((1 + 2)3)4)
  6. 我的代码如下。

    OPS = ('+', '-', '*', '/')
    def f(expr):
        """
        Generates FP exprs
        Recursive formula: f(expr1[op]expr2) = (f(expr1) [op] f(expr2))
        """
        if expr.isdigit(): yield expr
    #       return [expr]
    
    #   ret = []
        first = ''
        i = 0
        while i < len(expr):
            if expr[i] not in OPS:
                first += expr[i]
                i += 1
            else:
                op = expr[i]
                i += 1
                second = expr[i:]
                firstG, secondG = f(first), f(second)
                for e in ('(' + e1 + op + e2 + ')' for e1 in firstG for e2 in secondG):
                    yield e
    #               ret.append(e)
                first += op
    #    return ret
    

    如果我使用return语句(注释掉的行),则代码按预期工作。但是,当我在代码显示时更改为yield语句时,我只获得前4个结果。如果输入表达式的操作数的数量增加,那么当然会丢失更多结果。例如,对于输入'1+2+3+4+5',我只得到8而不是14。

    我终于找出了通过注释掉firstG, secondG = f(first), f(second)行并替换行

    来使代码工作的方法

    for e in ('(' + e1 + op + e2 + ')' for e1 in firstG for e2 in secondG):

    通过

    for e in ('(' + e1 + op + e2 + ')' for e1 in f(first) for e2 in f(second)):

    这意味着生成器的某些“信息”由于行firstG, secondG = f(first), f(second)而丢失,但我无法弄清楚真正的原因。你们能给我一些想法吗?

1 个答案:

答案 0 :(得分:4)

问题是你在生成器版本中迭代生成器而不是列表,特别是在一个循环后耗尽的 secondG 。将行更改为此,它可以工作:

firstG, secondG = f(first), list(f(second))

或者,您可以更改循环:

for e in ("(%s%s%s)" % (e1, op, e2) for e1 in f(first) for e2 in f(second)):
#                               new generator object every loop  ^^^^^^^^^

非收益版本的工作原理是因为您返回列表,与生成器不同,列表可以重复迭代。另请注意,您只需迭代 firstG 一次,因此不会受到影响。

请记住:

r = [v for a in A for b in B]

相当于:

r = []
for a in A:
  for b in B:
    r.append(v)

更清楚地显示了重复循环 B

另一个例子:

def y():
  yield 1
  yield 2
  yield 3
def r():
  return [1, 2, 3]

vy = y()
for v in vy:
  print v
for v in vy:
  print v

print "---"

vr = r()
for v in vr:
  print v
for v in vr:
  print v