[python] yield

gunny·2024년 3월 5일
0

Python

목록 보기
6/29

yield

python에서 제너레이터(Generator)를 생성할 때 사용되는 키워드

  • 제너레이터는 반복 가능한 객체(iterable)을 만들어 주는데, 값을 하나씩 생성해서 반환하고 그 상태를 기억해 함수의 실행을 일시 중단 할 수 있다. 이를 통해 메모리를 효율적으로 사용한다.

  • 'yield' 를 사용한 함수는 호출될 때 제너레이터 객체를 반환한다.
    이 객체는 실제로 함수 내의 코드를 실행하지 않는다. 대신에 값을 필요할 때마다 호출자에게 반환한다.
    함수의 실행은 'yield'에서 일시 중단되고, 호출자가 다음 값을 요청하면 다시 시작된다.

예를 들자면 0에서 시작해 무한히 증가하는 제너레이터를 만드는 함수 코드이다.

def infinite_generator():
	i = 0
    while True:
    	yield i
        i +=1
        
# 제너레이터 객체 생성
generator_obj = infinite_generator()

print(next(generator_obj)) #output 0
print(next(generator_obj)) #output 1
print(next(generator_obj)) $output 2

즉 위 코드에서 보듯이, yield i 는 현재 값을 반환하고 함수의 실행을 일시 중단한다.
그리고 next() 함수를 사용해 호출자는 제너레이터로부터 값을 요청하고, 함수의 실행이 중단된 지점에서 다시 시작하여 다음 값을 반환한다.

  • 'yield'는 반복 작업을 효율적으로 처리하고 메모리를 절약하는데 사용된다.
    대표적으로 대용량 데이터셋이나 연속적인 값을 생성해야 하는 상황에서 유용하다.

yield 사용 예시 basic

0부터 시작해서 주어진 limit 까지 짝수를 생성하는 제너레이터를 만든다면,

def generator_even_numbers(limit):
	i = 0
    while i <= limit:
    	if i%2==0:
        	yield i
        i+=1
 
even_generator = generator_even_numbers(10)

for number in even_generator:
	print(number)

yield i 는 현재 짝수를 반환하고 함수의 실행을 일시 중지한다.
호출자는 for 루프를 사용해 제너레이터로부터 값을 요청하면, 함수의 실행이 중단된 지점에서 다시 시작되어 다음 짝수를 생성하고 반환한다.
-> 이러한 방식으로 'yield'를 사용하면 대용량 데이터셋을 메모리에 모두 로드하지 않고 필요한 만큼만 생성하여 사용할 수 있다.

yield 대용량 데이터셋 로드 시 사용 예시

  • 예를 들어 파일에서 한 줄씩 데이터를 읽거오거나 외부 API 호출 시 비동기 작업을 수행하는 경우에 활용될 수 있다.
    아래의 코드는 파일에서 한 줄씩 데이터를 읽어오는 예제 코드인데, 대용량 로그 파일과 같은 경우 메모리를 효율적으로 사용할 수 있다.

def read_large_file(file_path):
	with open(file_path, 'r') as file:
    	for line in file:
        	yield line.strip()
            
# 파일에서 데이터를 읽어오는 제너레이터 객체 생성
log_reader = read_large_file('large_log_file.txt')

# 호출자에게 값을 하나씩 반환
for line in log_readers:
	print(line)
  • 위 코드에서 'read_large_file' 함수는 파일에서 한 줄씩 읽어오는 제너레이터를 생성한다.
    'yield line.strip()' 으로 현재의 줄을 반환하고 함수의 실행을 일시 중지한다.
    호출자는 for 루르플 사용해 제너레이터로부터 값을 요청하고, 함수의 실행이 중단죔 지점에서 다시 시작하여 다음 줄을 반환한다.

yield 비동기 작업 사용 예시

  • yield는 또한 비동기적인 작업에 사용되는 경우가 많다.
  • 비동기적 작업에서 'yield'를 사용하는 경우 보통 제너레이터를 활용해서 비동기 이벤트를 처리하거나, 비동기적으로 데이터를 가져오는 상황에서 사용된다.

예를 들어 'asyncio' 라이브러리를 사용해서 비동기적으로 웹 페이지를 가져온다고 가정한다면

import aiohttp
import asyncio

async def fetch_url(url):
	async with aiohttp.ClinetSession() as session:
    	async with sessionn.get(url) as response:
        	return await response.text()
            
async def async_data_generator(urls):
	for url in urls:
    	data = await fetch_url(url)
        yield data
        
# 비동기 작업을 위한 루프 
async def main():
	urls = ['http://example.com', 'http://example.org', 'http://example.net']
	
    async for data in async_data_generator(urls):
    	print(data)
        
# 이벤트 루프 실행
asyncio.run(main())

위에서 'fetch_url'은 비동기적으로 주어진 url에서 데이터를 가져오는 역할이다.
'asynco_data_generator' 함수는 여러 url에 대해 'fetch_url' 함수를 호출하고 가져온 데이터를 제러네이터를 통해 반환한다.
main 함수에서 'asynco_data_generator'를 비동기적으로 호출하고 가져온 데이터를 출력하고 있다.
위와 같이 'yield'와 비동기 작업을 결합하면 여러 비동기적인 이벤트나 작업을 효율적으로 처리할 수 있다.

profile
꿈꾸는 것도 개발처럼 깊게

0개의 댓글