StatCounter - Free Web Tracker and Counter

Effective Python Item 36. Iterator / Generator를 다룰 때는 itertools를 사용하라

반응형

들어가기 전

  • 이 글은 이펙티브 파이썬을 공부하며 작성한 글입니다. 

 


1. Itertools 라이브러리 

Itertools 라이브러리에는 이터레이터를 위한 몇 가지 기능들이 추가되어있다. 이터레이터와 관련된 코드가 복잡해지는 경우라면, itertools 라이브러리에서 원하는 기능을 지원하는지 살펴보는 것이 좋을 수 있다.

 


2. 여러 이터레이터 연결하기 

itertools에는 여러 이터레이터를 하나로 합치는데 사용할 수 있는 함수들이 지원된다. 

 

2.1 chain() 

it = itertools.chain([1,2,3], [4,5,6]) 
print(list(it))

>>> [1, 2, 3, 4, 5, 6]
  • 여러 이터레이터를 하나의 이터레이터를 합침. 

 

2.2 repeat() 

# 3번만 반복하는 Iterator 생성 
it = itertools.repeat('hello', 3)
print(list(it))
>>> ['hello', 'hello', 'hello']

# 무한히 반복하는 iterator 생성
c = 2
it = itertools.repeat('hello')
for i in it:
  print(i)
  if (c := c-1) == 0 :
    break
>> hello
>> hello
  • 한 값을 계속 반복해서 사용하고 싶을 때, repeat()를 사용한다. 
  • 2번째 인자에 최대 반복횟수를 정할 수 있음. 정하지 않는 경우 무한히 반복함. 

 

2.3. cycle() 

import itertools

it = itertools.cycle([1, 2, 3])
result = [next(it) for _ in range(10)]
print(result)

>>> [1, 2, 3, 1, 2, 3, 1, 2, 3, 1]
  • 특정 값들을 규칙적으로 반복하는 이터레이터를 만들고 싶을 때 사용할 수 있음. 

 

2.4. tee

it1, it2, it3 = itertools.tee(['one', 'two'], 3)
print(list(it1))
print(list(it2))
print(list(it3))

>>> ['one', 'two']
>>> ['one', 'two']
>>> ['one', 'two']
  • 한 이터레이터를 이용해 동일한 여러 이터레이터를 만들고 싶을 때, tee()를 사용한다. 
  • 이렇게 만들어진 이터레이터의 소모 속도가 동일하지 않은 경우, 아직 사용되지 않은 이터레이터의 원소를 보관해야하기 때문에 메모리 사용량이 늘어날 수 있다.

 

2.5. zip_longest

import itertools

keys = ['a', 'b', 'c']
values = [1, 2]

# 여러 이터레이터 동시에 이터레이팅. 
it = itertools.zip_longest(keys, values, fillvalue="no value")
print(list(it))

>>>
[('a', 1), ('b', 2), ('c', 'no value')]
  • 여러 이터레이터를 동시에 이터레이팅 하고 싶을 때 사용함. 
  • 긴 이터레이터를 기준으로 이터레이팅함. 
    • 이 때 짧은 이터레이터에는 fillvalue를 기준으로 값을 채워넣어줌. fillvalue의 기본값은 None임. 

 


3. 이터레이터에서 원소 필터링 

이터레이터에서 원소 필터링을 하는 함수가 지원된다. 

 

3.1 islice() 

import itertools

values = [n for n in range(1, 11)]

# stop = 5
it1 = itertools.islice(values, 5)
print(list(it1))

# start, stop, step
it2 = itertools.islice(values, 0, 5, 2)
print(list(it2))


>>
[1, 2, 3, 4, 5]
[1, 3, 5]
  • 이터레이터를 복사하지 않으면서 원소 인덱스를 이용해 슬라이싱 하고 싶을 때, islice()를 사용하면 됨.
    • stop만 지정하는 경우
    • start, stop, step을 지정하는 경우

위처럼 사용할 수 있음. 

 

3.2 takewhile() 

import itertools

values = [n for n in range(1, 11)]
less_than_seven = lambda x : x < 7
it = itertools.takewhile(less_than_seven, values)

print(list(it))

>>> 
[1, 2, 3, 4, 5, 6]
  • takewhile은 각 원소마다 주어진 함수로 원소를 평가하고, False를 처음 반환하는 원소를 만나는 경우 종료됨. 
  • False를 처음 반환하는 원소 이전의 원소들을 이터레이터로 반환함. 

 

 

3.3 dropwhile() 

import itertools

values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 6, 5, 4, 3, 2, 1]
less_than_seven = lambda x: x < 7
it = itertools.dropwhile(less_than_seven, values)

print(list(it))
>>>
[7, 8, 9, 10, 11, 6, 5, 4, 3, 2, 1]
  • dropwhile은 각 원소마다 주어진 함수로 원소를 평가하고, False를 처음 반환하는 원소를 찾을 때까지 모든 원소를 건너띔. 
  • False를 처음 반환하는 원소를 찾으면 그 원소 뒷쪽의 원소들 모두를 이터레이터로 반환함. (뒷쪽은 만족하지 않아도 상관없음) 

 

3.4 filterfalse

import itertools

values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 6, 5, 4, 3, 2, 1]
less_than_seven = lambda x: x < 7
it = itertools.filterfalse(less_than_seven, values)

print(list(it))

>>>
[7, 8, 9, 10, 11]
  • 내장 함수 Filter는 표현식이 true인 원소만 반환한다.
  • filterfalse는 표현식이 false인 원소만 반환한다.

 

 

댓글

Designed by JB FACTORY