[python] generator (제너레이터)

gunny·2024년 3월 5일
0

Python

목록 보기
7/29

Generator

먼저 generator에 대해 작성하기에 앞서, 참고해서 공부하고 있는 사이트에서 이터레이터를 언급하고 있다.

iterator(이터레이터, 반복자)

프로그래머가 컨테이너, 특히 목록을 탐색할 수 있게 해주는 객체

  • 이터레이터는 순회를 수행하고 컨테이너의 데이터 요소에 대한 엑세스는 제공하지만, 반복(iteration)은 수행하지 않는다.
  • 여기서 iterable(반복가능한 객체), 반복자(Iterator), 반복(Iteration) 이 나오는데, 이전 게시물에서 한 번 정리를 했었다.

https://velog.io/@heyggun/python-이터레이터-iterator-iter-getitem

무튼 짧게 정리하고 가자면, Iterable(순회 가능한 객체, 반복 가능한 객체) 는 iterator를 반환하고 인덱스를 취할 수 있는__iter__, __getitem__ 메소드가 정의된 파이썬의 객체이다.
iterator를 제공할 수 있는 객체라고 보면된다.

  • iterator(반복자)는 __next__ 메소드가 정의된 객체이다.
  • Iteration(반복) 은 배열과 같은 자료 구조에서 item, 원소를 가져오는 과정이다.

그렇다면 본격적으로 제너레이터에 대해서 알아보자.

generator(이하 제너레이터)

  • 제너레이터는 iterator(반복자)를 생성해주는 함수이다.
  • yield 키워드를 사용한다.
  • 제너레이터는 이터레이터이지만 단 한 번만 반복한다.
    메모리에 모든 값을 저장하지 않기 때문에 값을 사용할 때 즉시 생성한다.
    for loop를 사용하거나 반복하는 함수나 구조에 생성된 값들을 전달하여 반복을 통해 사용한다.
  • 대부분 제너레이터 들은 함수로 구현된다. 그러나 값을 반환하지 않고 yield(산출)될 뿐이다.

generator 특징

  • 모든 제너레이터는 Iterator 이면서 동시에 Iterable 한객체라는 것이다.
    제너레이터가 __iter____next__ 메서드를 내부적으로 구현하여 반복 가능한 객체로 동작할 수 있게 만들어 졌기 때문이다.

간단한 예로 0부터 시작해 무한히 증가하는 값을 생성하는 제너레이터 함수 코드를 보자면

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

# 반복 가능한지 확인
print(isinstance(gen_obj, Iterable)) # output True

# 값을 얻기 위해 반복
print(next(gen_obj)) # output 0
print(next(gen_obj)) # output 1
print(next(gen_obj)) # output 2
        
  • 여기서 infinite_generator 함수에서 생성된 gen_obj는 'Iterator' 이면서 'Iterable' 이다. 즉, for loop나 iter() 함수를 통해 순회가 가능하다는 의미이다.
  • next() 함수를 통해 제너레이터로부터 값도 얻고 있다.

따라서 모든 generator는 iterator로 iterable 순서가 지정된다는 것은
제너레이터는 반복가능한 객체이며 내부에서 __iter__, __next__를 구현하여 순회가능하고
next() 함수로 값을 생성한다는 의미이다.

generator의 사용

제너레이터는 모든 결과물들을 메모리에 저장하지 않으면서 동시에 많은 양의 결과 셋을 계산해야 할때 유용하다.

  • 주로 대용량 데이터를 처리하거나 연속적인 이벤트를 생성할때 사용한다.

[1] 로그 파일을 읽어오고 특정 조건을 만족하는 로그를 출력할 때 사용


def read_logs(log_file_path):
	with open(log_file_path, 'r') as file:
    	for line in file:
        	yield line.strip()
            
def filter_logs(logs, keyword):
	for log in logs:
    	if keyword in log:
        	yield log
            
def process_logs(logs):
	for log in logs:
    	yield f"Processed log: {log}"
        
# 로그 파일 경로 지정
log_file_path = 'example.log'

# 로그 파일을 읽어오는 제너레이터 생성
logs_generator = rea_logs(log_file_pth)

# 특정 키워드를 포함하는 로그를 필터링하는 제너레이터 생성
filtered_logs_generator = filter_logs(logs_generator, keyword='error')

# 로그를 가공하는 제너레이터 생성
process_logs_generator = process_logs(filtered_logs_generator)

# 최종적으로 제너레이터를 사용하여 출력

for processed_log in process_logs_generator:
	print(processed)log)
  • 위 코드에서 'read_logs' 함수는 로그 파일을 한 줄씩 읽어오는 제너레이터를 생성한다.
    그리고 'filter_logs'는 특정 키워드를 포함하는 로그만을 필터링하는 제러레이터를 생성한다.
    마지막으로 'process_logs' 함수는 로그를 가공하거나 다른 작업을 수행하는 제너레이터를 생성한다.
    이러한 제너레이터를 조합하여 로그 파일을 필터링하고 가공하는 프로세스를 구현한다.

[2] 데이터베이스에서 대량의 데이터를 읽어와서 처리할 때 사용

  • 파일이나 데이터베이스로부터 대용량 데이터를 읽어오는 상황이라고 가정했을 때
import random

def generator_large_data(size):
	for _ in range(size):
    	yield random.randint(1, 1000)
 
def process_large_data(data):
	for value in data:
    	yield f"Processed data : {value}"
        
# 대량의 데이터를 생성하는 제너레이터
large_data_generator = generator_large_data(1000000)

# 데이터를 가공하는 제너레이터 생성
processed_data_generator = process_large_data(large_data_generator)

# 최종적으로 제너레이터를 사용해서 출력(상위 5개)
for _ in range(5):
	processed_data = next(processed_data_generator)
    print(processed_data)
  • 위 코드에서 'generate_large_data' 함수로 가상의 대량 데이터를 생성하는 제너레이터를 생성하고, 'process_large_data' 함수는 받은 데이터를 가공하거나 다른 작업을 수행하는 제너레이터이다.
    위에서는 무작위로 생성한 가상 데이터를 사용했지만, 실제 서비스에서는 데이터베이스에서 데이터를 읽어오는 방식을 사용할 수 있다.

참고사이트

[1] https://ddanggle.gitbooks.io/interpy-kr/content/ch3-generators.html\

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

0개의 댓글