이제는 좀 구분하자! 파이썬 Iterable,

iterator, iterable 왜 알아야 할까?

1. 효율적인 메모리 사용

  • 이터러블이터레이터를 활용하면 큰 데이터를 메모리에 모두 올리지 않고도 처리할 수 있습니다. 이터레이터는 필요한 순간에만 데이터를 하나씩 가져오기 때문에, 대용량 데이터 처리 시 메모리 사용을 최소화할 수 있습니다.

  • 예를 들어, 100만 개의 요소를 가진 리스트를 모두 메모리에 올리는 대신, 이터레이터를 사용하여 한 번에 하나씩 요소를 처리하면 메모리 효율이 크게 향상됩니다.

2. 지연 평가(Lazy Evaluation)

  • 이터레이터는 필요할 때만 데이터를 생성하는 지연 평가를 지원합니다. 이는 성능을 최적화하고 불필요한 계산을 피할 수 있게 합니다.

  • 예를 들어, range() 함수는 실제 리스트를 생성하지 않고 이터레이터를 반환하여, 필요할 때만 숫자를 생성합니다. 이는 메모리와 시간 자원을 아끼는 데 유리합니다.

3. 커스터마이징과 확장성

  • 이터레이터이터러블을 이해하면, 직접 커스텀 이터레이터를 만들어 특정한 반복 동작을 정의할 수 있습니다. 예를 들어, 파일의 각 줄을 읽어들이거나, 무한히 값을 생성하는 이터레이터를 만들 수 있습니다.

  • 이를 통해 코드의 유연성과 재사용성을 높일 수 있습니다.

4. 파이썬의 기본 동작 원리 이해

  • 파이썬의 많은 내장 함수와 문법(예: for 루프, map(), filter(), zip())은 이터러블과 이터레이터를 기반으로 동작합니다. 이를 이해하면, 파이썬의 이러한 기본 기능들을 더 잘 활용할 수 있고, 어떤 상황에서 어떻게 동작하는지를 명확히 알 수 있습니

Iterable == 반복 가능한 객체

  • iterable == 한 번에 하나의 원소를 반환하는 객체! 만약에 반복문으로 해당 객체를 순회 할 수 있다면 그 객체는 iterable 하다고 할 수 있다(=iterable 객체이다)

  • 파이썬 공식문서에서 의하면 이터러블은 한 번에 하나의 원소를 반환하는 객체로 우리가 자주 사용하는 데이터 타입(list, dict, str)은 보통 iterable이라고 생각하면된다. for loop이나 zip, map에서 사용될 수 있다면 iterable 이다.

>>> for i in "abcd": # "abcd" 너도 iterable
...     print(i)
...
a
b
c
d
  • iterable은 내장함수 iter()의 입력으로 들어가고 출력으로 iterator가 나온다!‼‼‼ iter(iterable) -> iterator

  • 사용자가 만든 클래스에 __iter____getitem__이 정의되어있다면 모두 iterable이다

Iterator == 반복 가능한 객체(iterable)를 하나씩 순차적으로 처리하기 위해 사용되는 객체

  • iterator == 리스트, 튜플, 딕셔너리, 집합과 같은 반복 가능한 객체(iterable)를 하나씩 순차적으로 처리하기 위해 사용되는 객체

  • 내장함수 iter(iterable)의 반환값이고, 내장 함수 next(iterator)의 입력으로 들어갈 수 있다. iterable이 iterator 엄마다

  • iterator.__next__()를 반복적으로 호출하면 원소들이 순차적으로 반환된다!

cute_zoo = ['bear', 'lion', 'tiger'] # iterable
zoo_iterator = iter(cute_zoo) # iterator
print(zoo_iterator) # <list_iterator object at 0x105038d30>
print(next(zoo_iterator)) # cute_zoo 첫번째 원소 반환 -  bear
print(next(zoo_iterator)) # cute_zoo 두번째 원소 반환 - lion 
print(next(zoo_iterator)) # cute_zoo 세번째 원소 반환 - tiger
print(next(zoo_iterator))
>>> Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
  • 이터레이터에서 next를 통해 모든 원소를 다 순회하고 next() 호출 시 StopIteration 예외가 발생한다. 이 예외는 정상적인 동작으로, 이터레이터가 끝났다는 신호를 주는 역할을 한다

  • 그러나 이터러블 객체 자체는 직접적으로 요소를 하나씩 반환하지 않지만 이터레이터는 next()를 통해 이터러블 객체의 요소를 하나씩 순차적으로 반환 할 수 있다!

어? 근데 for loop에서 iterable사용해서 원소 하나씩 뽑을 수 있잖아?

  • iterator와 iterable의 가장 큰 차이점은 위에서 말씀드릴 것 처럼 직접 원소를 반환하는지의 여부였습니다.

  • 근데 이상하죠? for loop의 인자로 iterable이 들어가 원소를 하나씩 반환할 수 있는데!? -> 사실 for loop 내부적으로 iter를 호출해 원소들을 뽑아 준답니다. 파이썬 사용자들이 직접 iterator내 원소에 접근할려고 iter(이터러블)을 호출할필요가 없는거죠

      my_list = [0,1,2]
      for i in my_list:
          print(i)
    
    • for 루프가 시작되면, 내부적으로 파이썬은 먼저 이터러블 객체에 대해 iter()를 호출하여 이터레이터를 생성합니다.

    • 이터레이터는 이 리스트의 첫 번째 요소를 가리키는 상태로 초기화됩니다.

    • 그 다음, 루프가 반복될 때마다 이터레이터의 next() 메서드를 호출하여 다음 요소를 가져옵니다.

    • 모든 요소가 반환된 후에는 StopIteration 예외가 발생하지만, for 루프는 이 예외를 자동으로 처리하여 루프를 종료합니다.

코딩도장

iterable와 iterator의 차이

  • 이터러블 객체 자체는 직접적으로 요소를 하나씩 반환하지 않지만 이터레이터는 next()를 통해 이터러블 객체의 요소를 하나씩 순차적으로 반환 할 수 있다!

  • iterableiterator 를 포함한다 (이터러블이 더 큰 개념)

  • 모든 iterableiterator 를 만들 수 있다! (iter(이터러블객체) 반환 값이 iterator)

  •   >>> print(iter([1,2,3,4,5]))
      <list_iterator object at 0x106aa4a00>
    
  • 하지만 모든 iteratoriterable 이지만 그 역은 성립하지 않는다. (모든 이터러블이 이터레이터인것은아님)
>>> print(next([1,2,3,4,5]))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'list' object is not an iterator

[1,2,3,4,5] 는 iterable이다 하지만 iterator 가 아니기에 next의 인자가 될 수 없다!

  • 사용자 정의함수에서 iter() 를 구현했다면 -> iterable

  • 사용자 정의함수에서 iter()next() 를 둘 다 구현했다면 -> iterator