본문 바로가기
Language/Python

[Python] 제네레이터(Generator)를 이용한 itertools 예시

by 며루치꽃 2021. 12. 1.

병행성(Concurrency) : 한 컴퓨터가 여러 일을 동시에 수행

병렬성(Parallelistm) : 여러 컴퓨터가 여러 작업을 동시에 수행

 

단일 프로그램 안에서 여러 일을 쉽게 해결한다. 쓰레드는 한 개지만, 여러 일을 동시에 할 수 있기에 효율성이 매우 올라간다. 병행성에서 중요한 점은 하던 일을 기록해야한다는 점이다. 

def generator_ex1():
    print('Start')
    yield 'A Point.'
    print('continue')
    yield 'B Point.'
    print('End')

temp = iter(generator_ex1())

print(next(temp))
>>> Start
>>> A Point.
print(next(temp))
>>> continue
>>> B Point.
print(next(temp))
>>> End

- temp를 통해 generator_ex1() 를 제너레이터로 만든다.

- next를 호출하면 yield 키워드를 통해 A Point 에서 멈춰있다.

- next를 호출하면 yield 키워드를 통해 B Point 에서 멈춰있다.

- next를 호출하면 end가 끝나고 다음엔 나올 iterable한 객체가 없기 때문에 StopIteration 가 발생한다.

 

yield는 중단점을 설정하여 위치를 기억하고 있다. 이것이 여러 일을 동시에 수행하는 매커니즘이다. 예를 들어 인강을 듣다가 화장실을 가고 싶으면 공부하던 지점에 일시정지로 기록을 하고 화장실을 다녀오고 다시 시작한다.

이를 병행성에 적용해보면 예를 들어, 작업 시간이 오래걸리는 작업인 크롤링을 한다고 가정하면 yield를 통해 네이버 크롤링하는 것을 실행하게 두고 next를 통해 다음 실행할 작업을 하고 yield를 통해 구글 크롤링하는 것을 실행하게 두게 해준다. 

 

itertools 사용

Generator를 사용할 때 itertools이 매우 유용하다.

count()

import itertools

gen1 = itertools.count(1, 2.5) # 시작, 증가량

print(next(gen1)) 
>>> 1
print(next(gen1))
>>> 3.5
print(next(gen1))
>>> 6.0
print(next(gen1))
>>> 8.5
# ... 무한

print()

next() 를 통해 iterable 하게 사용할 수 있다.

 

takewhile()

gen2 = itertools.takewhile(lambda n : n < 1000, itertools.count(1, 2.5))

for v in gen2:
    print(v)
>>> 3, 4, 5

accumulate()

gen4 = itertools.accumulate([x for x in range(1, 10)])

for v in gen4:
    print(v)

>>> 1, 3, 6, 10, 15, 21, 28, 36, 45

chain()

gen5 = itertools.chain('ABCDE', range(1,11,2))

print(list(gen5))
>>> ['A', 'B', 'C', 'D', 'E', 1, 3, 5, 7, 9]

앞에 문자열을 split 한 것과 뒤의 원소를 연결하여 하나의 체인의 형태로 만들어준다

 

enumerate()

gen6 = itertools.chain(enumerate('ABCDE'))

print(list(gen6))
>>> [(0, 'A'), (1, 'B'), (2, 'C'), (3, 'D'), (4, 'E')]

index와 value를 연결하여 (index, iterable) 형태로 만들어 튜플형 리스트로 반환 

 

product() 

# 개별
gen7 = itertools.product('ABCDE')

print(list(gen7))
>>> [('A',), ('B',), ('C',), ('D',), ('E',)]

개별로 분리하여 튜플로 변환

repeat 옵션을 주면 순서쌍을 만들어준다.

 

# 연산(경우의 수)
gen8 = itertools.product('ABCDE', repeat=2)

# print(list(gen8))
>>> [('A', 'A'), ('A', 'B'), ('A', 'C'), ('A', 'D'), ('A', 'E'), ('B', 'A'), ('B', 'B'), ('B', 'C'), ('B', 'D'), ('B', 'E'), ('C', 'A'), ('C', 'B'), ('C', 'C'), ('C', 'D'), ('C', 'E'), ('D', 'A'), ('D', 'B'), ('D', 'C'), ('D', 'D'), ('D', 'E'), ('E', 'A'), ('E', 'B'), ('E', 'C'), ('E', 'D'), ('E', 'E')]

groupby() 

# 그룹화
gen9 = itertools.groupby('AAABBCCCCDDEEE')

# print(list(gen9))

for chr, group in gen9:
    print(chr, ' : ', list(group))

print()
>>>
A  :  ['A', 'A', 'A']
B  :  ['B', 'B']
C  :  ['C', 'C', 'C', 'C']
D  :  ['D', 'D']
E  :  ['E', 'E', 'E']

댓글