comprehension
1 2파이썬 comprehension
은 반복가능한 객체(iterable object)를 생성하는 방법으로 이를 통해서 리스트, 집합(set), 딕셔너리, 생성자(generator)를 생성시킬 수 있다. Comprehension
이란 반복가능한(iterable)한 객체를 생성시키는 파이썬에서 자주 사용하는 방법으로 자료형에 따라 다음과 같이 나눠진다.
comprehensions
3List comprehensions
에 대한 적절한 번역은 없는 상황이라 ‘리스트 축약’ 혹은 ’리스트 포함’이라고 번역하는 경우가 가끔있고 그냥 영어로 List comprehensions
을 사용한다.
리스트로 숫자가 담긴 객체 numbers
가 있다 모든 숫자에 2를 곱하고자 하는 경우 다음과 같이 2를 곱한 연산 결과를 담을 리스트 객체 res_number
를 만들어 생성시킨다. 그리고 나서 리스트 각 원소를 꺼내 2를 곱한 후에 .append()
메쏘드로 각 계산된 값을 채워넣는다.
numbers = [1,2,3,4,5]
res_number = []
for number in numbers:
res_number.append(number * 2)
print(res_number)
[2, 4, 6, 8, 10]
for
문장으로 작성한 코드가 list comprehension
으로 작성하게 되면 2줄이 한 줄로 준 것을 확인할 수 있다.
[2, 4, 6, 8, 10]
list comprehension
은 표현식, 반복변수, 반복자로 구성되어 for
루프를 한줄로 간결하게 표현할 수 있도록 도움을 준다.
number * 2
number
numbers
list comprehension
먼저 list comprehension
을 사용해서 1–10사이 숫자를 리스트에 담아둔다. 조건문(conditional
)을 list comprehension
뒤에 붙여 1 – 10까지 숫자 중 짝수와 홀수만 발라낸다. %
는 나머지 연산자를 사용해서 2로 나눠 0과 1을 기준으로 홀수와 짝수로 구분한다.
전체 숫자: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
짝수: [2, 4, 6, 8, 10]
홀수: [1, 3, 5, 7, 9]
if
조건문을 앞으로 가져와서 if-else
조합을 하게 되면 짝수만 남겨두고 홀수를 0으로 대체하는 것이 가능하다.
only_even_numbers = [number if number % 2 == 0 else 0 for number in whole_numbers]
print(f"짝수: {only_even_numbers}")
짝수: [0, 2, 0, 4, 0, 6, 0, 8, 0, 10]
for
루프튜플 리스트를 생성하는데 for
루프를 사용하는 것과 리스트 comprehension을 사용하는 경우를 비교하여 보자.
다중 for
루프
먼저 문자와 숫자를 조합하여 튜플을 만들고 이를 이중 for
루프를 사용해서 튜플 리스트로 작성한다.
letters = ['X', 'Y', 'Z']
numbers = [1, 2, 3]
results = []
for letter in letters:
for number in numbers:
results.append((letter, number))
print(results)
[('X', 1), ('X', 2), ('X', 3), ('Y', 1), ('Y', 2), ('Y', 3), ('Z', 1), ('Z', 2), ('Z', 3)]
리스트 comprehension
튜플 리스트를 이중 for
루프를 사용하는 것과 비교하여 한줄로 단순화 시킬 수 있다.
[('X', 1), ('X', 2), ('X', 3), ('Y', 1), ('Y', 2), ('Y', 3), ('Z', 1), ('Z', 2), ('Z', 3)]
위키백과사전 Bag-of-words model에 포함된 단어주머니 모형을 리스트 comprehension을 사용해서 구현해본다.
bow_text
string
팩키지 string.punctuation
와 조건을 갖는 comprehension을 사용해서 구두점을 제거한다.set()
함수로 집합을 생성시키고 이를 튜플의 키로 사용한다.sorted()
함수를 사용해서 key=
를 값으로 지정하고 역순으로 정렬하여 출력시킨다.import string
# 예제 문장
bow_text = 'John likes to watch movies. Mary likes movies too. John also likes to watch football games.'
# 소문자 변환 후 단어 쪼개기
bow_text_stripped = ''.join(c for c in bow_text if not c in string.punctuation) # 구두점 제거
bow_list = bow_text_stripped.lower().split()
# 단어 집합
bow_set = set(bow_list)
# 단어 갯수 세기
bow_tup_list = [ (word, bow_list.count(word)) for word in bow_set ]
# 리스트 튜플 정렬
sorted(bow_tup_list, key = lambda x: x[1], reverse=True)
[('likes', 3), ('john', 2), ('to', 2), ('movies', 2), ('watch', 2), ('mary', 1), ('also', 1), ('football', 1), ('games', 1), ('too', 1)]
난수를 0-10 사이 난수를 5개씩 추출하는데 중복을 방지하고자 set()
함수를 사용한다. 그리고 fractions
라이브러리 gcd()
함수를 사용해서 두 리스트 사이 최대공약수를 뽑아낸다.
# 두 리스트에서 최대공약수 찾아내기
import random
from random import randint
random.seed(777)
list_one = list(set([randint(0,10) for i in range(5)]))
list_two = list(set([randint(0,10) for j in range(5)]))
print("첫번째 리스트:", list_one, "\n두번째 리스트", list_two)
## 최대공약수
첫번째 리스트: [9, 3, 5, 7]
두번째 리스트 [0, 4, 5, 7, 8]
[(9, 4), (9, 5), (9, 7), (9, 8), (3, 4), (3, 5), (3, 7), (3, 8), (5, 4), (5, 7), (5, 8), (7, 4), (7, 5), (7, 8)]
다른 방법은 최대공약수를 재귀(recursion)를 사용하는 것이다.
def gcd_recur (x, y):
if y == 0:
return x
else:
return gcd_recur(y, x % y)
[(i,j) for i in list_one
for j in list_two if gcd_recur(i,j) == 1]
[(9, 4), (9, 5), (9, 7), (9, 8), (3, 4), (3, 5), (3, 7), (3, 8), (5, 4), (5, 7), (5, 8), (7, 4), (7, 5), (7, 8)]
comprehension
dictinary comprehension
은 동일하고 [
대신에 {
을 사용한다는 측면에서 차이가 난다. 짝수면 2로 나누고 홀수면 -1을 곱하여 음수로 만든 딕셔너리를 만들어낸다.
dict_numbers = {number / 2 if number % 2 == 0 else -number for number in whole_numbers}
print(f"딕셔너리 매직: {dict_numbers}")
딕셔너리 매직: {1.0, 2.0, 3.0, 4.0, 5.0, -9, -7, -5, -3, -1}
리스트(list)
와 딕셔너리(Dictionary)
를 다음표를 통해서 비교할 수 있다.
리스트(list) | 딕셔너리(Dictionary) |
---|---|
[] 을 사용해서 선택, 갱신, 제거 |
[] 을 사용해서 선택, 갱신, 제거 |
숫자 범위를 index 로 사용 |
유일무이한 키를 index 로 사용 |
값(value)들을 모아놓은 것, 순서가 있음 | 유일무이한 키를 갖는 lookup 테이블 |