본문 바로가기

매직 메서드 - 반복

1. 반복 가능한 객체

파이썬에서는 for 루프를 만나면 해당되는 객체의 __iter__를 실행합니다. 그리고 __next__를 순차적으로 실행합니다. 이를 풀면 아래와 같은 코드가 됩니다.

for i in 'hello':
    print(i)
my_iterator = iter('hello') # __iter__ 실행, for 루프에서 실행
i = next(my_iterator) # __next__ 실행
print(i)
i = next(my_iterator)
print(i)
i = next(my_iterator)
print(i)
i = next(my_iterator)
print(i)
i = next(my_iterator)
print(i)
i = next(my_iterator)
print(i) # StopIteration 예외 발생, 반복문 탈출

2. __iter__, __next__ 매직 메서드

파이썬에서는 __iter__ 매직 메서드를 사용하여 반복 가능한 객체를 만들 수 있습니다. 이 메서드는 __next__ 메서드를 가진 이터레이터 객체를 반환해야 합니다.

class MyRange:
    def __init__(self, start, end):
        self.start = start
        self.end = end

    def __iter__(self):
        return self

    def __next__(self):
        if self.start >= self.end:
            raise StopIteration
        value = self.start
        self.start += 1
        return value

my_range = MyRange(0, 3)
for i in my_range:
    print(i)

다만 이렇게 순회를 하면 한 번만 순회할 수 있습니다. 이를 해결하기 위해서는 이터레이터를 새로 만들어야 합니다.

3. 이터레이터 재사용

이터레이터를 재사용하고 싶다면 __iter__ 메서드에서 self.current_value 변수를 초기화해야 합니다.

class MyIterator:
    def __init__(self, stop):
        self.stop = stop

    def __iter__(self):
        self.current_value = 0  # __iter__에서 초기화
        return self

    def __next__(self):
        if self.current_value >= self.stop:
            raise StopIteration
        result = self.current_value
        self.current_value += 1
        return result

my_iterator = MyIterator(5)

for i in my_iterator:
    print(i)

for i in my_iterator:
    print(i)

💡 위 코드는 https://pythontutor.com/python-debugger.html#mode=edit 서비스를 통해 시각화해서 단계별로 실행해보면서 이해하시길 권해드립니다.

4. 이터러블과 이터레이터 분리

이 두가지 용어를 혼동하기 쉽지만, 이터러블은 __iter__ 메서드를 가진 객체를 말하고, 이터레이터는 __next__ 메서드를 가진 객체를 말합니다.

우리가 흔히 순회가능한 객체라고 부르는 것은 이터러블 객체입니다. 이 두개를 아래처럼 분리할 수도 있습니다.

class NumberIterator:
    def __init__(self, start, end):
        self.current = start
        self.end = end
    
    def __next__(self):
        if self.current >= self.end:
            raise StopIteration
        value = self.current
        self.current += 1
        return value

class Numbers:
    def __init__(self, start, end):
        self.start = start
        self.end = end
    
    def __iter__(self):
        return NumberIterator(self.start, self.end)

nums = Numbers(1, 4)

# 첫 번째 반복
for num in nums:
    print(f"첫번째: {num}")

# 두 번째 반복 (새로운 이터레이터가 생성됨)
for num in nums:
    print(f"두번째: {num}")

5. yield를 사용한 이터레이터

yield 키워드를 사용하면 이터레이터를 간단하게 만들 수 있습니다.

class EvenNumbers:
    def __init__(self, end):
        self.end = end
    
    def __iter__(self):
        for i in range(0, self.end, 2):
            yield i

evens = EvenNumbers(7)
for num in evens:
    print(num)  # 0, 2, 4, 6
매직 메서드 - 반복 - 파이썬 클래스 톺아보기 | 위니버시티