IT박스

yield를 사용한 재귀

itboxs 2020. 12. 15. 08:27
반응형

yield를 사용한 재귀


재귀와 yield을 혼합하는 방법이 있습니까? 예를 들어 무한 수 생성기 (재귀 사용)는 다음과 같습니다.

def infinity(start):
    yield start
    # recursion here ...

>>> it = infinity(1)
>>> next(it)
1
>>> next(it)
2

나는 시도했다 :

def infinity(start):
    yield start
    infinity(start + 1)

def infinity(start):
    yield start
    yield infinity(start + 1)

그러나 그들 중 누구도 내가 원하는 것을하지 않았습니다. 첫 번째는 항복 start하고 두 번째는 항복 start한 다음 발전기를 멈췄습니다.

참고 : while 루프를 사용하여이 작업을 수행 할 수 있다는 것을 알고 있습니다.

def infinity(start):
    while True:
        yield start
        start += 1

나는 이것이 재귀 적으로 수행 될 수 있는지 알고 싶습니다.


예, 다음과 같이 할 수 있습니다.

def infinity(start):
    yield start
    for x in infinity(start + 1):
        yield x

그러나 최대 재귀 깊이에 도달하면 오류가 발생합니다.

Python 3.3부터 다음을 사용할 수 있습니다.

def infinity(start):
    yield start
    yield from infinity(start + 1)

생성기 함수를 반복하거나 yield from-ing 하지 않고 재귀 적으로 호출 하면 실제로 함수 본문을 실행하거나 아무것도 생성하지 않고 새 생성기를 빌드하기 만하면 됩니다.

자세한 내용은 PEP 380참조 하십시오.


경우에 따라 생성기에 재귀 대신 스택을 사용하는 것이 더 나을 수 있습니다. 스택과 while 루프를 사용하여 재귀 메서드를 다시 작성할 수 있어야합니다.

다음은 콜백을 사용하고 스택 논리를 사용하여 다시 작성할 수있는 재귀 메서드의 예입니다.

def traverse_tree(callback):
    # Get the root node from somewhere.
    root = get_root_node()
    def recurse(node):
        callback(node)
        for child in node.get('children', []):
            recurse(child)
    recurse(root)

위의 방법은 각 노드에 children자식 노드를 포함 할 수 있는 배열이 있는 노드 트리를 순회합니다 . 각 노드가 발견되면 콜백이 발행되고 현재 노드가 전달됩니다.

이 방법은 각 노드에서 일부 속성을 인쇄하는 방식으로 사용할 수 있습니다.

def callback(node):
    print(node['id'])
traverse_tree(callback)

대신 스택을 사용하고 순회 메소드를 생성기로 작성하십시오.

# A stack-based alternative to the traverse_tree method above.
def iternodes():
    stack = [get_root_node()]
    while stack:
        node = stack.pop()
        yield node
        for child in reversed(node.get('children', [])):
            stack.append(child)

(Note that if you want the same traversal order as originally, you need to reverse the order of children because the first child appended to the stack will be the last one popped.)

Now you can get the same behavior as traverse_tree above, but with a generator:

for node in iternodes():
    print(node['id'])

This isn't a one-size-fits-all solution but for some generators you might get a nice result substituting stack processing for recursion.


def lprint(a):
    if isinstance(a, list):
        for i in a:
            yield from lprint(i)
    else:
        yield a

a = [[1, [2, 3], 4], [5, 6, [7, 8, [9]]]]
for i in lprint(b):
    print(i)

So basically you just need to add a for loop at where you need to call your function recursively. This applies for Python 2.7.

ReferenceURL : https://stackoverflow.com/questions/8991840/recursion-using-yield

반응형