|

파이썬 yield return 차이: generator는 왜 한 번에 다 만들지 않을까

파이썬 yield return generator 차이 대표 이미지
yield는 값을 한 번에 모두 돌려주는 대신, 필요할 때 하나씩 만들어 내는 흐름을 만듭니다.

yield return 차이는 Python generator를 이해할 때 꼭 잡아야 하는 기준입니다. `return`은 익숙하지만, `yield`는 값을 돌려주는 것처럼 보이면서도 함수가 바로 끝나지 않는다는 점이 다릅니다.

핵심은 return은 한 번에 끝내고, yield는 값을 하나씩 내보내며 실행 위치를 기억한다는 것입니다. 이 글은 Python 공식 문서의 generator와 yield expression 설명을 기준으로 예제와 사용 기준을 정리합니다.

파이썬 yield와 return 차이 요약 카드
return은 함수 실행을 끝내고, yield는 값을 내보낸 뒤 다시 이어서 실행할 수 있게 합니다.

yield return 차이를 먼저 보기

`return`은 함수의 결과를 돌려주고 실행을 끝냅니다. 반면 `yield`는 값을 하나 내보내고 함수의 실행 상태를 멈춰 둡니다. 다음 값을 요청받으면 멈췄던 위치 다음부터 다시 실행합니다.

def numbers():
    yield 1
    yield 2
    yield 3

for n in numbers():
    print(n)

`numbers()`를 호출하면 리스트가 아니라 generator object가 만들어집니다. 실제 코드는 반복이 시작되어 다음 값을 요청할 때 실행됩니다.

return은 한 번에 결과를 만든다

일반 함수는 실행 결과를 한 번에 만들어 반환합니다. 작은 데이터나 즉시 계산이 끝나는 값에는 이 방식이 단순하고 좋습니다.

def make_numbers():
    return [1, 2, 3]

values = make_numbers()
print(values)

리스트는 모든 값이 메모리에 들어 있습니다. 값이 적으면 문제가 없지만, 아주 큰 데이터라면 처음부터 모두 만드는 비용이 커질 수 있습니다.

yield는 필요한 만큼 하나씩 만든다

generator는 값을 미리 전부 만들지 않고, 요청받을 때마다 다음 값을 만들어 냅니다. 이런 흐름을 lazy evaluation이라고 부르기도 합니다.

def count_up_to(limit):
    n = 1
    while n <= limit:
        yield n
        n += 1

for value in count_up_to(3):
    print(value)

yield는 큰 데이터를 한 번에 담지 않고 흐름으로 처리할 수 있게 해 줍니다. 그래서 파일 줄 단위 처리, 스트림 처리, 긴 반복 데이터 생성에 잘 맞습니다.

큰 파일 처리 예시

큰 파일을 모두 읽어 리스트로 만든 뒤 처리하면 메모리를 많이 쓸 수 있습니다. 한 줄씩 읽고 필요한 값만 yield하면 소비하는 쪽은 반복문으로 자연스럽게 처리할 수 있습니다.

def read_error_lines(path):
    with open(path, "r", encoding="utf-8") as file:
        for line in file:
            if "ERROR" in line:
                yield line.rstrip("\n")

for error in read_error_lines("app.log"):
    print(error)

이 코드는 error line을 전부 리스트에 모으지 않습니다. 반복하는 동안 필요한 줄만 하나씩 넘깁니다.

generator는 한 번 소진되면 다시 처음으로 가지 않는다

generator는 iterator입니다. 한 번 끝까지 소비하면 다시 반복해도 값이 나오지 않습니다. 다시 처음부터 돌고 싶다면 generator 함수를 다시 호출해야 합니다.

gen = numbers()
print(list(gen))  # [1, 2, 3]
print(list(gen))  # []

print(list(numbers()))  # 새 generator

return과 함께 쓸 때의 의미

generator 함수 안에서도 `return`을 쓸 수 있습니다. 이때 return은 generator를 끝내는 역할을 합니다. 일반 함수처럼 호출자에게 리스트나 값을 바로 돌려주는 흐름과는 다르게 읽어야 합니다.

def limited():
    yield 1
    return
    yield 2  # 실행되지 않음

언제 yield를 쓰면 좋을까

  • 데이터가 크고 한 번에 모두 만들 필요가 없을 때
  • 값을 순서대로 하나씩 생성하는 로직일 때
  • 파일, 로그, 스트림을 줄 단위로 처리할 때
  • 중간 결과를 반복문에 자연스럽게 넘기고 싶을 때

실무 체크리스트

  1. 결과 전체가 꼭 리스트여야 하는지 확인한다
  2. 한 번에 모두 만들면 메모리 부담이 큰지 본다
  3. 소비하는 쪽이 반복문으로 처리할 수 있는지 확인한다
  4. generator가 한 번만 소비된다는 점을 문서화한다
  5. 디버깅이 어려워질 정도로 yield 흐름을 과하게 나누지 않는다

정리

파이썬 `return`은 함수를 끝내고 결과를 돌려줍니다. `yield`는 generator를 만들고, 값을 하나씩 내보내며 실행 상태를 이어갈 수 있게 합니다.

함께 보면 좋은 Python 흐름 제어 글은 파이썬 with 문과 context manager 이해하기, 파이썬 args kwargs 차이, 파이썬 asyncio는 언제 필요할까입니다. 외부 기준은 Python Tutorial – Generators, Python Reference – Yield expressions, Python Glossary – Iterator를 확인했습니다.

함께보면 좋은 글