본문 바로가기
language/Python

[Python] Iterable, Iterator 개념과 예제 및 iterator 직접 만들기

by 스파이디웹 2022. 3. 2.
728x90

1. Iterator

  • 순서대로 다음 값을 리턴할 수 있는 객체를 의미
  • Iterator는 자체적으로 내장하고 있는 next 메소드를 통해 다음 값을 가져올 수 있음

2. Iterable

  • 내부 요소(member)를 하나씩 리턴할 수 있는 객체
  • Iterable한 것은 __next__ 메소드가 존재하지 않음
  • 내부에 __Iter__라는 메소드를 가지고 있음
  • for문을 통해 순회할 수 있는 객체를 Iterable하다고 함

컬렉션 타입(컨테이너 타입)

set, dictionary와 같이 여러개의 요소(객체)를 갖는 데이터 타입

시퀀스 타입

list, tuple, range, str등과 같이 순서가 존재하는 데이터 타입

 

위의 타입들은 전부 iterable하지만, iterator는 아니다.

a = list()
b = set()
c = "str"
d = dict()
e = tuple()
f = range(1,3)

#print(a.__next__) AttributeError: 'list' object has no attribute '__next__'
#print(b.__next__) AttributeError: 'set' object has no attribute '__next__'
#print(c.__next__) AttributeError: 'str' object has no attribute '__next__'
#print(d.__next__) AttributeError: 'dict' object has no attribute '__next__'
#print(e.__next__) AttributeError: 'tuple' object has no attribute '__next__'
#print(f.__next__) AttributeError: 'range' object has no attribute '__next__'

Iterable한 객체 To Iterator

iterable한 객체를 iter()메소드를 통해 Iterator로 만들 수 있음

a = [1,2,3]
#리스트는 iterator가 아니다.
#print(a.__next__) 실행시 오류발생
a = iter(a)
print(type(a))# list_itertor 출력
print(a.__next__())# 첫 실행 시 1출력
print(next(a))#다음과 같은 방법으로도 출력이 가능하다. 2출력
print(a.__next__())#3출력
#print(a.__next__())#StopIteration출력

a.__next__()를 통해 iterator의 index범위 밖으로 나가게 되면, StopIteration Exception 발생하게 된다.

 


 

for문과 Iterator

파이썬의 for문은 내부적으로 Iterator를 생성하여 동작(__iter__ 메소드 이용)

 

ex)

리스트를 순회하는 for문

  • 해당 리스트의 Iterator를 생성한 다음 __next__메소드를 이용해 순회를 도는 방식
  • StopIteration을 만나기 전까지 순회를 돔

 


직접 iterator, iterable 만들기

__iter__메소드를 구현한 클래스를 통해 Iterable한 객체를 만들 수 있고, __next__메소드를 구현한 클래스를 통해 Iterator를 만들 수도 있다.

 

2개의 숫자를 입력받아 시작 값부터 종료 값까지 1씩 증가하는 Iterator를 생성

#Iterable한 객체를 만들 수 있는 클래스
class Iterable:
    def __init__(self, start_number, stop_number):
        self.start_number = start_number #시작 값
        self.stop_number = stop_number # 종료 값

    def __iter__(self):
        return Iterator(self.start_number, self.stop_number)

class Iterator:
    def __init__(self, start_number, stop_number):
        self.start_number = start_number #시작 값
        self.current_number = start_number #현재 값
        self.stop_number = stop_number  # 종료 값

    def __next__(self):
        if self.current_number < self.stop_number:
            self.current_number += 1
            return self.current_number
        else:
            raise StopIteration

test = Iterable(5,20).__iter__() #test를 iterable 인스턴스로 만든 후 __iter__메소드 호출
print(type(test))
for i in range(5,25):
    try:
        print(test.__next__())
    except:
        print("StopIteration 발생")

위의 코드는 아래와 같이 출력된다.

위의 코드를 하나의 클래스로 통합시킬 수도 있다.

#iterable과 iterator를 같이 구현한 class
class IterableAndIterator:
    def __init__(self, start_number, stop_number):
        self.stop_number = start_number # 시작 값 지정
        self.stop_number = stop_number # 종료 값 지정
        self.current_number = start_number # 현재 값 지정

    def __iter__(self):
        return self # 자기 자신 객체를 리턴

    def __next__(self):
        if self.current_number < self.stop_number:
            self.current_number += 1
            return self.current_number
        else:
            raise StopIteration

test2 = IterableAndIterator(5,20)
print(type(test2))
for i in range(5,25):
    try:
        print(test2.__next__())
    except:
        print("StopIteration 발생")


결론:

  1. Iterable은 내부에 __iter__메소드를 가지고 있음
  2. __next__ 메소드로 다음 값을 반환할 수 있으면 Iterator, 없으면 Iterable한 객체
  3. iterable 객체를 iter()를 통해 iterator로 만들 수 있음
  4. iterator는 StopIteration을 만나기 전까지 __next__메소드를 이용해 순회를 돔
  5. iterable객체 및 iterator를 __iter__ 및 __next__메소드를 생성하여 직접 만들 수 있다.

 

728x90

댓글