returnyield는 Python에서 함수의 동작 방식에 큰 차이를 만드는 두 키워드입니다.

이 두 키워드의 차이점과 언제 사용하는지에 대한 이해를 하기 위하여 아래와 같은 구조로 설명할 수 있습니다.

 

Python에서 returnyield는 함수의 실행을 제어하는데 사용되지만, 그 방식과 결과는 크게 다릅니다.

returnyield의 차이점을 살펴보겠습니다.

 

1. return의 동작 방식

정의: return은 함수에서 값을 반환하고, 함수의 실행을 종료하는 키워드입니다.

함수가 return을 만나면, 그 즉시 실행이 종료되고 값이 호출자에게 반환됩니다.

용도: 보통 함수가 어떤 결과값을 계산하고 그 값을 반환할 때 사용됩니다. 그 값은 단순히 반환된 결과로만 활용됩니다.

 

예시: 

def add(a, b):
    return a + b

result = add(3, 5)
print(result)  # 출력: 8

 

이처럼 return을 만나면 즉시 결과값이 반환되고 종료됩니다.

 

2. yield의 동작 방식

정의: yield는 함수에서 값을 반환하는 것처럼 보이지만, 함수의 실행을 잠시 멈추고 해당 지점까지의 상태를 기억합니다.

함수는 yield를 만나면 중간에 멈추고 그 시점까지의 값을 호출자에게 반환하지만, 함수의 실행이 종료되지 않고, 다시 호출되었을 때 이전 상태에서 계속 실행을 이어갑니다. 즉, 호출자에게 제어권을 넘겨준다고 생각하시면 됩니다.

 

용도: yield는 데이터를 한 번에 하나씩 생성하거나 반복할 때 유용합니다. 주로 제너레이터(generator)를 만들 때 사용됩니다.

 

예시:

def yield_test():
    for i in range(5):
        yield i
        # 함수 내에서 요소에 해당하는 부분을 yield 에 넣으면 됨
        print(i,'번째 호출!')
print(type(yield_test())) # <class 'generator'>

 

# __next__() 함수를 통해 출력
t = yield_test()
print(t.__next__()) # 0
print(t.__next__()) # 0 번째 호출! 1
print(t.__next__()) # 1 번째 호출! 2
print(t.__next__()) # 2 번째 호출! 3
print(t.__next__()) # 3 번째 호출! 4
# print(t.__next__()) #Error
# 함수를 완전 실행시키는 것이 아니라 일부를 실행시키고 일시 정지 -> 호출한 쪽으로 제어권 전달

range(5)를 주었기 때문에 __next__()를 호출하면 yield에서 0을 반환하고 함수가 멈춘 상태로 대기합니다.

두 번째 호출 시, yield 다음 줄부터 실행이 재개되며 print() 문에서 "0 번째 호출!"을 출력한 뒤, yield에서 1을 반환하고 다시 대기합니다.

이 과정을 반복하며, 마지막(i=4)에서 "3 번째 호출!"을 출력한 뒤 yield에서 4를 반환하고 대기합니다.

즉, 제어권을 yield에게 주어 print가 다음으로 찍히지 않습니다. 이 후 한번 더 호출하면 for 루프가 끝나면서 함수가 종료되고 

StopIteration 예외가 발생합니다.

 

출력:

0
0 번째 호출!
1
1 번째 호출!
2
2 번째 호출!
3
3 번째 호출!
4

 

그러나, 다음은 for문에서 제너레이터를 사용할때의 동작방식입니다.

#for문을 이용하여 출력
print("<-->")
for k in yield_test():
    print(k)

여기서 4번째 출력까지 출력되는 이유는 k에 값을 할당하고 print문으로 출력하기 때문입니다. yield가 실행된 후 대기하지 않고 k에 값을 할당하며 바로 print(k)가 출력된다는 내용입니다.

출력:

<-->
0
0 번째 호출!
1
1 번째 호출!
2
2 번째 호출!
3
3 번째 호출!
4
4 번째 호출!

3. return과 yield의 주요 차이점 정리

  return yield
동작 방식 값을 반환하고 함수 종료 값을 반환하지만 함수는 종료되지 않음
용도 하나의 값 또는 결과를 반환 반복적으로 값을 생성하는 데 사용
반환 값 반환된 값을 단순히 받음 제너레이터 객체를 반환
기억되는 상태 함수 실행이 종료되므로 상태 저장 안됨 함수의 상태(변수 값 등)가 기억됨
성능 한 번에 전체 값 반환 메모리 효율적 (필요한 값만 반환)

 

4. 결론

 화자는 주로 return을 사용하지만 yield는 주로 큰 데이터를 다룰때 사용하면 메모리 절약에 좋습니다.

예를 들어서 100만개의 데이터를 사용한다고 할때 한꺼번에 큰 데이터를 메모리에 올리면 속도와 컴퓨팅(자원)비용 이슈가 있을 수 있기 때문에 필요한 숫자를 한번에 하나씩 생성해서 메모리 관리에 쓸때 사용하면 좋은 yield를 활용합니다.

파일 read나 API 응답 같은 데이터 스트리밍을 처리할때도 yield를 사용하면 좋습니다.

# readlines() 사용 예시 (비효율적)
with open("big_file.txt", "r") as f:
    lines = f.readlines()  # 파일 전체를 메모리에 읽어들임

# 모든 줄을 한꺼번에 메모리에 올리니까 큰 파일에는 메모리 문제 발생 가능
def read_large_file(file_path):
    with open(file_path, "r") as f:
        for line in f:
            yield line.strip()  # 한 줄씩 반환

for line in read_large_file("big_file.txt"):
    print(line)  # 한 줄씩 출력 (메모리 부담 없음)

Ref.

https://j-sik.tistory.com/126

 

반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기