Coder/파이썬 Python

[Python] Iterable 과 Iterator의 차이

개요

최근 빅쿼리를 사용하여 슬랙봇을 개발할 일이 있었습니다.

빅쿼리 테이블에서 쿼리한 결과를 보기 좋게 편집하여 슬랙을 보내는 배치 서비스를 개발하는 중에 헷갈렸던 파이썬 개념이 있어 정리해 보려고 합니다.

 

*해당 글은 다음 기준으로 작성되었습니다.

python~=3.10
google-cloud-bigquery~=3.9.0

 

 

빅쿼리 패키지에서 쿼리 결과를 객체로 받아 사용하는 여러 가지 방법이 있습니다.

그중에서도 bigquery.Client.query().result()라는 함수를 사용하여 리턴되는 bigquery.table.rowiterator 객체를 바로 사용하려고 했었으나,

for문 실행 중에 ‘iterator has already started'라는 오류가 발생하였습니다. 😭

 

파이썬의 기본 개념 중 하나인 iterator를 2번 이상 호출할 수 없다는 사실을 잊어버렸던 것이죠!

객체를 반복문에 사용하는 경우 iterator 객체의 재사용 여부가 중요하다는 것을 다시 한번 깨달았습니다.

결국은 iterator 객체를 다시 iterable한 객체(list)로 변환하여 사용하였습니다. 

 

단순히 iterable 하다는 것과 iterator의 차이점을 함께 알아봅시다. 😉

 

 

Iterable 하다는 것은?

내부 요소를 하나씩 리턴할 수 있는 객체를 말합니다.

하지만 iterator를 제외한 iterable 한 객체는 __next__ 메소드가 존재하지 않고, 내부에 __iter__ 메소드가 존재합니다.

 

for문에 iterator가 아닌 iterable한 객체를 사용하는 경우, 파이썬이 자동으로 iterator로 임시 변수를 생성하여 작업을 수행하기 때문에 우리는 직접 iter로 변경하지 않아도 됩니다.

 

예시

  • 보통 for 문을 순회할 수 있는 객체인 list, set, dict, tuple, range 등은 모두 iterable 하다고 말할 수 있습니다.
    • 하지만 iterator는 아닙니다.
  • iterator도 iterable하다고 말합니다.

 

공식 문서 설명은 다음과 같습니다. (링크)

iterable

An object capable of returning its members one at a time. Examples of iterables include all sequence types (such as list, str, and tuple) and some non-sequence types like dict, file objects, and objects of any classes you define with an __iter__() method or with a __getitem__() method that implements Sequence semantics.

Iterables can be used in a for loop and in many other places where a sequence is needed (zip(), map(), …). When an iterable object is passed as an argument to the built-in function iter(), it returns an iterator for the object. This iterator is good for one pass over the set of values. When using iterables, it is usually not necessary to call iter() or deal with iterator objects yourself. The for statement does that automatically for you, creating a temporary unnamed variable to hold the iterator for the duration of the loop. See also iterator, sequence, and generator.

 

 

Iterator란?

순서대로 다음 요소 값을 리턴할 수 있는 객체를 의미합니다.

 

자체적으로 내장하고 있는 __next__ 메소드를 이용하여 다음 요소를 리턴할 수 있습니다.

더 이상 사용할 수 있는 다음 요소가 없으면, StopIteration exception이 발생합니다.

 

중요한 것은 이 시점에서 iterator 객체는 소진된다는 것입니다. 추가로 호출할 경우 계속 StopIteration이 발생합니다.

 

공식 문서에서도 이를 명시적으로 주의하라고 언급하고 있습니다.

여러 번 반복을 시도하는 코드를 작성할 경우 iterator 사용을 주의해야 합니다.

제가 겪었던 문제는 바로 이를 주의하지 않아서 발생한 것이었습니다!

 

위의 iterable 설명에서 언급했던 것처럼, list 같은 iterable 객체는 for 문에서 사용할 때마다 새로운 임시 iterator를 생성합니다.

하지만 iterator로 이 작업을 시도하면, 임시 객체를 만들지 않습니다.

 

다시 말하자면, 이전의 반복문에서 사용했던 것과 동일한, 이미 소진된 iterator 객체가 반환되므로 exception이 발생합니다.

 

예시

  • 예를 들어 내장함수 중 하나인 filter는 함수가 참을 반환하는 iterable의 요소로부터 iterator를 구축하여 객체로 리턴합니다.

 

공식 문서 설명은 다음과 같습니다. (링크)

iterator

An object representing a stream of data. Repeated calls to the iterator’s __next__() method (or passing it to the built-in function next()) return successive items in the stream. When no more data are available a StopIteration exception is raised instead. At this point, the iterator object is exhausted and any further calls to its __next__() method just raise StopIteration again. Iterators are required to have an __iter__() method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted. One notable exception is code which attempts multiple iteration passes. A container object (such as a list) produces a fresh new iterator each time you pass it to the iter() function or use it in a for loop. Attempting this with an iterator will just return the same exhausted iterator object used in the previous iteration pass, making it appear like an empty container.

More information can be found in Iterator Types.

 

 

Iterable 를 Iterator 로 변환하기

앞서 언급한 것처럼 iterable한 객체는 __iter__ 메소드를 내장하고 있습니다.

이를 이용하여 iterator로 변환할 수 있습니다. 또는 파이썬 내장함수인 iter()를 이용할 수도 있습니다.

 

list_example = ['member1', 'member2', 'member3']

iterator_from_list_ex1 = list_example.__iter__()
type(iterator_from_list_ex1)
# <class 'list_iterator'>

iterator_from_list_ex2 = iter(list_example)
type(iterator_from_list_ex2)
# <class 'list_iterator'>

 

마무리

오늘은 파이썬의 기본 개념인 Iterable과 Iterator의 차이에 대해서 알아보았습니다.

기본 개념이지만, 실제로 업무에서 객체의 유형을 정확하게 파악하고 있어야 하므로 중요하다고 생각됩니다.

저도 이번에 글로 정리하면서 다시 헷갈리지 않도록 개념이 잘 정립된 것 같네요. 😄

글을 읽은 분들도 모두 차이점에 대해 확실히 이해하고 가셨으면 좋겠습니다!

 

 

글의 내용 중 틀린 부분 또는 궁금한 부분이 있다면 편하게 댓글로 말씀 부탁드립니다:)

 

 

레퍼런스

 

Glossary — Python 3.10.11 documentation

The implicit conversion of an instance of one type to another during an operation which involves two arguments of the same type. For example, int(3.15) converts the floating point number to the integer 3, but in 3+4.5, each argument is of a different type

docs.python.org

 

 

Class QueryJob (3.4.0)  |  Python client library  |  Google Cloud

Send feedback Class QueryJob (3.4.0) Stay organized with collections Save and categorize content based on your preferences. Version latest keyboard_arrow_down QueryJob(job_id, query, client, job_config=None) Asynchronous job: query tables. ParametersNameDe

cloud.google.com