Please Enable JavaScript!
Gon[ Enable JavaScript ]

파이썬 Python 제너레이터와 이터레이터 사용하기

파이썬 Python
반응형

 

파이썬에서 **제너레이터(generator)**와 **이터레이터(iterator)**는 큰 데이터를 효율적으로 처리하거나 지연 평가(lazy evaluation)를 구현할 때 유용하게 사용됩니다. 제너레이터와 이터레이터는 메모리를 효율적으로 사용하며, 데이터가 필요할 때마다 하나씩 생성하여 반환하는 방식으로 동작합니다.

 

 


1. 이터레이터 (Iterator)

이터레이터반복 가능한 객체에서 순차적으로 요소를 반환하는 객체입니다. 파이썬에서 __iter__()와 __next__() 메서드를 구현한 객체는 이터레이터로 사용할 수 있습니다.

이터레이터 기본 사용 예제

# 리스트에서 이터레이터 생성
numbers = [1, 2, 3]
iterator = iter(numbers)

# next()를 통해 요소를 순차적으로 가져오기
print(next(iterator))  # 결과: 1
print(next(iterator))  # 결과: 2
print(next(iterator))  # 결과: 3
# print(next(iterator))  # StopIteration 오류 발생

설명: iter() 함수는 반복 가능한 객체에서 이터레이터를 반환하며, next() 함수를 사용해 각 요소를 순차적으로 가져옵니다. 요소를 모두 가져오면 StopIteration 예외가 발생하여 반복이 끝났음을 알립니다.


2. 사용자 정의 이터레이터 만들기

__iter__()와 __next__() 메서드를 가진 클래스를 만들어 이터레이터를 정의할 수 있습니다.

class MyIterator:
    def __init__(self, max_value):
        self.current = 0
        self.max_value = max_value

    def __iter__(self):
        return self

    def __next__(self):
        if self.current < self.max_value:
            self.current += 1
            return self.current - 1
        else:
            raise StopIteration

# 이터레이터 사용
my_iter = MyIterator(3)
for number in my_iter:
    print(number)  # 결과: 0, 1, 2

설명: MyIterator 클래스는 __next__() 메서드에서 self.current 값을 반환하며, self.current가 max_value에 도달하면 StopIteration을 발생시켜 반복을 종료합니다.


3. 제너레이터 (Generator)

제너레이터는 함수처럼 작성되지만, 데이터를 반환할 때 return 대신 yield 키워드를 사용하여 데이터를 하나씩 반환합니다. 제너레이터는 값을 "지연 생성"하므로 메모리를 효율적으로 사용할 수 있습니다.

제너레이터 기본 사용 예제

def my_generator():
    yield 1
    yield 2
    yield 3

gen = my_generator()

print(next(gen))  # 결과: 1
print(next(gen))  # 결과: 2
print(next(gen))  # 결과: 3
# print(next(gen))  # StopIteration 오류 발생

설명: yield 키워드는 값을 반환하고 함수의 실행 상태를 유지합니다. 다시 호출되면 이전 상태에서 실행을 이어가며 다음 yield까지 진행합니다. 제너레이터가 값을 모두 반환하면 StopIteration이 발생합니다.


4. 제너레이터와 for 문 사용

제너레이터는 for 문에서 자동으로 이터레이터로 동작하며, StopIteration을 처리할 필요 없이 순차적으로 모든 값을 출력할 수 있습니다.

def my_generator():
    for i in range(3):
        yield i

for value in my_generator():
    print(value)  # 결과: 0, 1, 2

설명: 제너레이터는 for 문과 함께 사용할 때 자동으로 StopIteration을 처리해 반복을 종료합니다.


5. 제너레이터 표현식

제너레이터는 컴프리헨션 방식으로도 정의할 수 있으며, 이는 메모리를 효율적으로 사용하는 지연 생성 리스트와 유사한 역할을 합니다.

gen_exp = (x * x for x in range(5))
print(list(gen_exp))  # 결과: [0, 1, 4, 9, 16]

설명: gen_exp는 제너레이터 표현식으로 정의되며, x * x 결과를 순차적으로 반환합니다. 이를 리스트로 변환하여 모든 값을 한 번에 출력할 수 있습니다.


6. 제너레이터를 활용한 무한 수열 생성

제너레이터는 필요할 때까지 데이터를 생성하여 반환하므로, 무한히 큰 데이터도 메모리 부담 없이 처리할 수 있습니다.

def infinite_sequence():
    num = 0
    while True:
        yield num
        num += 1

gen = infinite_sequence()
print(next(gen))  # 결과: 0
print(next(gen))  # 결과: 1
print(next(gen))  # 결과: 2
# 계속해서 값을 반환함

설명: infinite_sequence 제너레이터는 무한히 큰 수열을 생성합니다. next() 함수를 호출할 때마다 num이 1씩 증가해 무한히 값을 반환합니다.


7. 제너레이터로 큰 데이터 처리하기

제너레이터는 데이터를 한 번에 메모리에 올리지 않고, 필요한 만큼만 생성하여 반환하기 때문에 대용량 파일이나 큰 데이터셋을 처리할 때 유용합니다.

def read_large_file(file_path):
    with open(file_path, "r") as file:
        for line in file:
            yield line.strip()

for line in read_large_file("large_file.txt"):
    print(line)  # 파일의 각 줄을 순차적으로 처리

설명: read_large_file 제너레이터는 파일을 한 줄씩 읽어 반환하므로, 메모리를 절약하면서 대용량 파일을 처리할 수 있습니다.


8. 제너레이터와 yield from

yield from 구문을 사용하면 다른 제너레이터나 반복 가능한 객체에서 값을 간편하게 가져올 수 있습니다.

def generator1():
    yield from range(3)
    yield from "ABC"

for value in generator1():
    print(value)

결과:

0
1
2
A
B
C

설명: yield from은 제너레이터를 중첩 호출할 때 사용되며, range(3)과 "ABC"의 모든 값을 순차적으로 반환합니다.


요약

  • 이터레이터는 __iter__()와 __next__() 메서드를 구현한 객체로, next() 함수를 통해 값을 순차적으로 반환합니다.
  • 제너레이터는 yield 키워드를 사용하여 데이터를 "지연 생성"하며, 메모리 효율적으로 대용량 데이터를 처리할 수 있습니다.
  • 제너레이터 표현식을 사용하면 지연 생성 리스트처럼 작동하는 제너레이터를 간단히 생성할 수 있습니다.
  • 무한 수열 생성이나 대용량 파일 처리 등에 제너레이터를 활용하면 메모리 효율성을 크게 높일 수 있습니다.

제너레이터와 이터레이터를 활용하면 데이터 처리 효율을 높이고, 메모리 사용을 최소화할 수 있습니다.

반응형
Posted by 녹두장군1
,