본문 바로가기

Python_programming/초중급편

파이썬 이터레이터(iterator)와 이터러블(iterable) 차이점

많이들 헷갈려하는 개념들을 정리해보았습니다. 

제 이해를 쉽게 하기 위한 정리이기에 틀린 부분이 있을 수 있습니다. 

정정해줄 부분이 있다면 댓글로 가르침을 주시면 감사하겠습니다 :) 

 

1)  이터레이션(iteration) 

 

어떤 객체의 원소에 하나씩 차례로 접근하는 것. 명시적으로든 암묵적으로든 반복문을 사용해 객체의 여러 원소에 하나하나 접근하면 그것은 이터레이션(iteration)이다.

 

Iteration is a general term for taking each item of something, one after another. Any time you use a loop, explicit or implicit, to go over a group of items, that is iteration.

 

일단 '이터레이션'이라고 하면 '반복'문을 떠올리고 상상하자. 

 

2) 이터러블(Iterable) :반복 가능한 객체

  • __iter__

3) 이터레이터(iterator): 값을 차례대로 꺼낼 수 있는 객체

  • __iter__
  • __next__

 

보통 이런식의 설명과 메서드들을 통해 구분합니다. 근데 뭔가 아리송합니다...

 

자, 이제 코드로 보면서 설명하겠습니다.

 

 

 

 

 

조금 후려쳐서 말하겠습니다. 메서드를 기준으로 next 가 되면 iterator, next 메서드가 안되면 iterable 입니다. 

위 코드에서 sample 변수는 리스트입니다. 근데 next 메서드가 없다고 하네요. 그러면 이 변수는 iterable 입니다. 

근데 재밌는 점은 iterable 객체를 iterator 로 바꿀 수 있습니다. 

 

이터레이터에는 __iter__() 라는 메서드가 있기 때문입니다. 

이제 이터레이터 객체를 iter() 메서드를 통해서 이터레이터로 바꿔보겠습니다.  (아래 코드 참고)

 

 

 

 

 

이터러블 객체를 이터레이터로 바꿨습니다. 어떻게? 

이터러블 객체의 메서드인 iter() 를 통해서!

 

이터레이터는 __next__로 요소를 계속 꺼내다가 꺼낼 요소가 없으면 StopIteration 예외를 발생시켜서 반복을 끝냅니다.

 

물론, 리스트뿐만 아니라 문자열, 딕셔너리, 세트도 __iter__를 호출하면 이터레이터가 나옵니다. 그리고 이터레이터에서 __next__를 호출하면 차례대로 값을 꺼냅니다. (아래 참고) 

 

 

 

 

 

 

 

자, 그러면 for 문에서 리스트를 쓰면 하나씩 나오는데 이터러블은 next가 없는데 어떻게 그게 가능해? 

라고 생각할 수 있습니다. 

 

아래 동작 과정을 보시면 다음과 같이 for range(3)을 사용했다면 먼저 range에서 __iter__로 이터레이터를 얻습니다. 그리고 한 번 반복할 때마다 이터레이터에서 __next__로 숫자를 꺼내서 i에 저장하고, 지정된 숫자 3이 되면 StopIteration을 발생시켜서 반복을 끝냅니다. 

 

 

출처: https://dojang.io/mod/page/view.php?id=2405

 

 

이처럼 반복 가능한 객체(이터러블)는 __iter__ 메서드로 이터레이터를 얻고, 이터레이터의 __next__ 메서드로 반복합니다. 여기서는 반복 가능한 객체와 이터레이터가 분리되어 있지만 클래스에 __iter__ __next__ 메서드를 모두 구현하면 이터레이터를 만들 수 있습니다. 특히 __iter__, __next__를 가진 객체이터레이터 프로토콜(iterator protocol)을 지원한다고 말합니다.

 

이터러블 -> __iter__ -> 이터레이터 -> __next__

 

차이를 아시겠네요? 이 개념들은 말로 이해하면 조금 헷갈립니다. (저의 경우는 그랬습니다) 

메서드를 통해서 이해하는 게 저는 정리가 쉽게 되서 정리해보았습니다. 

 

핵심은 이터러블은 __iter__ 메서드를 통해서 이터레이터로 변할 수 있다. 

 

근데 왜 이렇게 설계했지? 라고 한다면 아래 예시를 보겠습니다. 

 

for i in range(100):

 

0부터 99까지 연속된 숫자를 만들어내는 반복문입니다. 사실은 숫자를 모두 만들어 내는 것이 아니라 0부터 99까지 값을 차례대로 꺼낼 수 있는 이터레이터를 하나만 만들어냅니다. 이후 반복할 때마다 이터레이터에서 숫자를 하나씩 꺼내서 반복합니다.

 

만약 연속된 숫자를 미리 만들면 숫자가 적을 때는 상관없지만 숫자가 아주 많을 때는 메모리를 많이 사용하게 되므로 성능에도 불리합니다. 그래서 파이썬에서는 이터레이터만 생성하고 값이 필요한 시점이 되었을 때 값을 만드는 방식을 사용합니다. 즉, 데이터 생성을 뒤로 미루는 것인데 이런 방식을 지연 평가(lazy evaluation)라고 합니다.

 

일단 쉽게 생각합시다. 이터레이터는 메모리 효율을 위해서 쓴다라고 생각하면 편합니다. (물론 제너레이터가 있죠...ㅎㅎ) 

 

+) 시퀀스 객체와 반복 가능한 객체는 무슨 차이?

 

리스트, 튜플, range, 문자열(바이트 객체)은 반복 가능한 객체이면서 시퀀스 객체입니다. 하지만, 딕셔너리와 세트는 반복 가능한 객체이지만 시퀀스 객체는 아닙니다. 왜냐하면 시퀀스 객체는 요소의 순서가 정해져 있고 연속적(sequence)으로 이어져 있어야 하는데, 딕셔너리와 세트는 요소(키)의 순서가 정해져 있지 않기 때문입니다. 따라서 시퀀스 객체가 반복 가능한 객체보다 좁은 개념입니다. 즉, 요소의 순서가 정해져 있고 연속적으로 이어져 있으면 시퀀스 객체, 요소의 순서와는 상관없이 요소를 한 번에 하나씩 꺼낼 수 있으면 반복 가능한 객체입니다.

 

코딩도장에 나온 위 설명에 보충합니다.

시퀀스 객체는 인덱싱과 슬라이싱이 됩니다. 

순서적으로 데이터가 되어있는게 시퀀스 객체이기에 인덱싱과 슬라이싱은 될 수밖에 없습니다. { 실제로도 그렇구요:) }

이제 이터러블과 이터레이터의 개념이 좀 잡혔으니 공식 문서에 나온 정의를 읽어보면서 마무리하겠습니다.

 

iterable (이터러블)

멤버들을 한 번에 하나씩 돌려줄 수 있는 객체. 이터러블의 예로는 모든 (list,str,tuple같은) 시퀀스 형들,dict같은 몇몇 비 시퀀스 형들,파일 객체들,__iter__()시퀀스개념을 구현하는__getitem__()메서드를 써서 정의한 모든 클래스의 객체들이 있습니다.

이터러블은for루프에 사용될 수 있고, 시퀀스를 필요로 하는 다른 많은 곳 (zip(),map(), …) 에 사용될 수 있습니다. 이터러블 객체가 내장 함수iter()에 인자로 전달되면, 그 객체의 이터레이터를 돌려줍니다. 이 이터레이터는 값들의 집합을 한 번 거치는 동안 유효합니다. 이터러블을 사용할 때, 보통은iter()를 호출하거나, 이터레이터 객체를 직접 다룰 필요는 없습니다.for문은 이것들을 여러분을 대신해서 자동으로 해주는데, 루프를 도는 동안 이터레이터를 잡아둘 이름 없는 변수를 만듭니다.이터레이터,시퀀스,제너레이터도 보세요.

 

iterator (이터레이터)

데이터의 스트림을 표현하는 객체. 이터레이터의__next__()메서드를 반복적으로 호출하면 (또는 내장 함수next()로 전달하면) 스트림에 있는 항목들을 차례대로 돌려줍니다. 더 이상의 데이터가 없을 때는 대신StopIteration예외를 일으킵니다. 이 지점에서, 이터레이터 객체는 소진되고, 이후의 모든__next__()메서드 호출은StopIteration예외를 다시 일으키기만 합니다. 이터레이터는 이터레이터 객체 자신을 돌려주는__iter__()메서드를 가질 것이 요구되기 때문에, 이터레이터는 이터러블이기도 하고 다른 이터러블들을 받아들이는 대부분의 곳에서 사용될 수 있습니다. 중요한 예외는 여러 번의 이터레이션을 시도하는 코드입니다. (list같은) 컨테이너 객체는iter()함수로 전달하거나for루프에 사용할 때마다 새 이터레이터를 만듭니다. 이런 것을 이터레이터에 대해서 수행하려고 하면, 지난 이터레이션에 사용된 이미 소진된 이터레이터를 돌려줘서, 빈 컨테이너처럼 보이게 만듭니다.

이터레이터 형에 더 자세한 내용이 있습니다.

 

https://docs.python.org/ko/3/glossary.html

 

용어집 — Python 3.8.2 문서

같은 형의 두 인자를 수반하는 연산이 일어나는 동안, 한 형의 인스턴스를 다른 형으로 묵시적으로 변환하는 것. 예를 들어, int(3.15)는 실수를 정수 3으로 변환합니다. 하지만, 3+4.5 에서, 각 인자는 다른 형이고 (하나는 int, 다른 하나는 float), 둘을 더하기 전에 같은 형으로 변환해야 합니다. 그렇지 않으면 TypeError를 일으킵니다. 코어션 없이는, 호환되는 형들조차도 프로그래머가 같은 형으로 정규화해주어야 합니다, 예를 들어

docs.python.org

 

 

 

--참고--

 

https://dojang.io/mod/page/view.php?id=2405

 

파이썬 코딩 도장: 39.1 반복 가능한 객체 알아보기

Unit 39. 이터레이터 사용하기 이터레이터(iterator)는 값을 차례대로 꺼낼 수 있는 객체(object)입니다. 지금까지 for 반복문을 사용할 때 range를 사용했습니다. 만약 100번을 반복한다면 for i in range(100):처럼 만들었습니다. 이 for 반복문을 설명할 때 for i in range(100):은 0부터 99까지 연속된 숫자를 만들어낸다고 했는데, 사실은 숫자를 모두 만들어 내는 것이 아니라 0부터 99까지 값을 차례

dojang.io

 

https://jiminsun.github.io/2018-05-11/Iteration/

 

https://stackoverflow.com/questions/9884132/what-exactly-are-iterator-iterable-and-iteration