본문 바로가기

Python/중급

Python - 중급 04 (iterator)

python의 iterator는 뭘까요? 한 마디로 next()를 사용 하여 다음 요소를 가져올 수 있는 객체를 의미합니다. 이해가 안되시죠? 하나씩 알아보도록 하겠습니다.

먼저, 반복 가능(iterable)하다는 것은?

iterable 하다는 것은 여러 값이 그룹화 되어 있는 데이터 구조에서 요소를 하나씩 꺼내어 사용할 수 있다는 의미입니다. 이러한 데이터 구조는 list, tuple, dictionary, set 등이 있습니다. for문으로 값을 읽어 올 수 있으면 iterable 하다고 할 수 있습니다.

a = [1, 2, 3, 4, 5]
# a = (1, 2, 3, 4, 5)
# a = {1, 2, 3, 4, 5}
# a = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

for i in a:
    print(i)

그럼, iterator는 무엇인가?

제일 처음 iteator를 말씀 드릴 때 next 함수를 사용 한다고 말씀 드렸습니다. 다른 각도로 next 함수로 다음 요소를 가져 올 수 없으면 iterator가 아닙니다. 그럼 위의 iterable한 객체를 next를 사용 하여 호출 해보겠습니다.

a = [1, 2, 3, 4, 5]

print(next(a))

아래와 같은 에러가 발생합니다.

TypeError: 'list' object is not an iterator

음~~ list는 iterator가 아니라고 합니다. list는 iterable한 객체이지만 iterator는 아니라는 의미입니다. tuple, dictionary, set도 마찬가지 입니다. 그럼 iterator는 어떻게 만들 수 있을까요?

iter()로 생성 할 수 있습니다.

iterabla한 객체를 iter()에 전달하면 iterator를 생성 할 수 있습니다.

a = [1, 2, 3, 4, 5]
it = iter(a)

print(it)

print(next(it))
print(next(it))
print(next(it))
print(next(it))
print(next(it))

print(next(it))

위의 코드를 실행하면 아래와 같은 결과가 출력됩니다.

<list_iterator object at 0x7f8f6c1b5d90>
1
2
3
4
5
Traceback (most recent call last):
  File "main.py", line 11, in <module>
    print(next(it))
  • iter()로 형변환 한 it을 출력 하면 list_iterator object가 출력됩니다.
  • next()로 값을 하나씩 가져올 수 있습니다.
  • 다음 요소가 없는데도 next()를 호출하면 StopIteration 에러가 발생합니다.

iterator의 특징

  • next() 함수를 사용하여 다음 요소를 가져올 수 있습니다.
  • 다음 요소가 없는데도 next()를 호출하면 StopIteration 에러가 발생합니다.
  • iterator는 모든 값을 한 번에 반환하지 않고 필요할 때마다 하나씩 반환합니다. 이를 lazy evaluation이라고 합니다.
  • iterator는 모든 값을 메모리에 저장하지 않고 필요할 때마다 값을 생성합니다.
  • iterator는 한 번 사용하면 다시 사용 할 수 없습니다.
  • iterator는 for문에서 사용할 수 있습니다.

iter()를 사용하지 않고 iterator를 생성 할 수 있을까요?

직접 iterator를 생성 할 수 있습니다. iter()를 통해 iterator를 반환하고 next()를 통해 다음 요소를 가져오도록 구현하면 됩니다.
class를 사용하여 iterator를 생성해 보겠습니다.

class Countdown:
    def __init__(self, start):
        self.current = start  # 초기화 때 입력 받은 값을 현재 값으로 설정

    def __iter__(self):
        return self       # 자기 자신을 반환 - Countdown 객체가 iterator가 됨

    def __next__(self):   # iterator의 다음 요소를 반환
        if self.current <= 0: # 현재 값이 0보다 작거나 같으면(다음 요소가 없을 때를 정의)
            raise StopIteration # StopIteration 에러 발생
        else:
            num = self.current  # 현재 값을 반환
            self.current -= 1   # 다음 요소를 위해 현재 값을 1 감소
            return num

it_counter = Countdown(3)  # 초기값을 3으로 Countdown 객체 생성
print(it_counter)

# next 함수 호출
print(next(it_counter))
print(next(it_counter))
print(next(it_counter))

# StopIteration 에러 발생
print(next(it_counter))

위의 코드를 실행하면 아래와 같은 결과가 출력됩니다.

<__main__.Countdown object at 0x7f6f93ad7dc0>
3
2
1
Traceback (most recent call last):
  File "main.py", line 25, in <module>
    print(next(it_counter))
  File "main.py", line 9, in __next__
    raise StopIteration
StopIteration

매직 메소드(magic method) 또는 스페셜 메소드(special method)

매직 메소드는 클래스 내부에서 사용되며 __로 시작하고 __로 끝납니다.

__iter__

  • 객체가 "반복 가능(iterable)"임을 나타냅니다.
  • 반복을 위한 iterator 객체를 반환해야 합니다.
  • 이 메서드가 반환하는 객체는 __next__ 메서드를 구현해야 하며, 이는 보통 iterator 객체 자신입니다.

__next__

  • iterator 객체의 핵심 부분으로, 반복에서 다음 요소를 반환합니다.
  • 이 메서드가 호출될 때마다, iterator는 컬렉션의 다음 요소를 반환해야 합니다.
  • 더 이상 반환할 요소가 없을 때 StopIteration 예외를 발생시켜야 합니다.
  • for 루프와 같은 반복 구조는 StopIteration 예외를 만나면 반복을 종료합니다.

연습 문제

  • 0부터 주어진 n까지의 숫자를 순차적으로 반환하는 iterator를 만드세요. 예를 들어, n=5일 때 iterator는 0, 1, 2, 3, 4, 5를 순차적으로 반환해야 합니다.
class Countdown:
    def __init__(self, start):
        self.current = start  # 초기화 때 입력 받은 값을 현재 값으로 설정

    def __iter__(self):
        return self       # 자기 자신을 반환 - Countdown 객체가 iterator가 됨

    def __next__(self):   # iterator의 다음 요소를 반환
        if self.current <= 0: # 현재 값이 0보다 작거나 같으면(다음 요소가 없을 때를 정의)
            raise StopIteration # StopIteration 에러 발생
        else:
            num = self.current  # 현재 값을 반환
            self.current -= 1   # 다음 요소를 위해 현재 값을 1 감소
            return num

for i in Countdown(5):
    print(i)

아래는 generator를 사용하여 구현한 예시입니다.
generator는 Python - 중급 05 (generator)를 참조 하십시오.

def countdown(n):
    i = n
    while i >= 0:
        yield i
        i -= 1

for i in countdown(5):
    print(i)

'Python > 중급' 카테고리의 다른 글

Python - 중급 06 (closure)  (0) 2024.01.10
Python - 중급 05 (generator)  (0) 2024.01.10
Python - 중급 03 (lambda)  (0) 2024.01.10
Python - 중급 02 (map, filter, reduce)  (0) 2024.01.10
Python - 중급 01 (list comprehension)  (0) 2024.01.10