Я действительно не понимаю как yield
оператор работает в этой ситуации. Проблема говорит, что, учитывая выражение без круглых скобок, запишите функцию для генерации всех возможных выражений полностью заключенного в скобки (FP). Скажите, вход '1+2+3+4'
который должен быть сгенерирован к 5 выражениям FP:
Мой код следующие.
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)
но я не могу выяснить настоящую причину. Могли Вы парни давать мне некоторое представление?
Проблема заключается в том, что вы итализация по поводу генераторов вместо списков в версии выхода, в частности , вторые , который исчерпан после одного цикла. Измените строку к этому, и это работает:
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 ^^^^^^^^^
версия не доходности работает, поскольку вы возвращаете списки, которые можно повторить, в отличие от генераторов. Также отметим, что вы только за пределы один раз, поэтому он не затронут.
Помните, что это:
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