dict
) 자료형¶사전(dict
, dictionary) 자료형은 키(key)와 키에 할당된 값(value)으로
이루어진 쌍들의 집합으로 생각할 수 있다.
영어 사전을 '영어 단어'와 '단어의 뜻'으로 이루어진 쌍들의 집합으로 볼 수 있다는 것과 유사하다는 의미에서 사전 자료형이라 불린다. 실제로 '영어 단어'를 키(key)로, '단어의 뜻'을 해당 단어의 값(value)으로 이해할 수 있다.
사전 자료형을 나타내는 기호는 집합기호인 중괄호({}
)이며,
빈 사전은 아래와 같이 생성한다.
empty_dict1 = dict()
빈 사전을 아래와 같이 공집합 기호를 사용할 수도 있지만, 혼란 방지를 위해 위 방식을 추천한다.
empty_dict2 = {}
type(empty_dict2)
dict
dict
자료형은 보통 아래 형태이다.
grades = {"Joel": 80, "Tim": 95}
특정 키에 해당하는 값을 확인하려면 리스트의 인덱싱처럼 대괄호를 사용한다. 다만 인덱스 숫자 대신에 키 이름을 사용한다.
예를 들어, "Joel"
의 점수(grade)를 확인하려면 다음과 같이 실행한다.
grades["Joel"]
80
없는 키를 사용하면 오류가 발생한다.
try:
kates_grade = grades["Kate"]
except KeyError:
print("Kate 점수가 없어요!")
Kate 점수가 없어요!
키의 존재여부는 in
연산자를 이용해서 확인한다.
"Joel" in grades
True
"Kate" in grades
False
dict
자료형의 get
메소드를 사용하면 키가 존재하지 않아도 오류가 발생하지 않는다.
키가 존재하면 해당 값을 리턴한다.
grades.get("Joel")
80
키가 존재하지 않으면 논(None
)을 리턴한다.
grades.get("Kate")
주의:
None
은 '아무 값도 아니다'를 의미하는 일종의 값이다. C, Javd 등의 널(null) 값에 해당한다.
따라서 함수를 실행해도 아무 것도 보여주지 않는다.return
) 키워드가 없는 경우
None
을 반환값으로 사용한다.get
메소드는 둘째 인자를 받을 수 있으며, 해당 키가 존재하지 않을 경우 None
대신에 지정된 둘째 인자를 반환한다.
키가 존재하면 둘째 인자는 무시된다.grades.get("Kate", "해당 키가 없어요")
'해당 키가 없어요'
grades.get("Joel", 0)
80
print(grades)
{'Joel': 80, 'Tim': 95}
grades["Tim"] = 99
grades["Kate"] = 100
print(grades)
{'Joel': 80, 'Tim': 99, 'Kate': 100}
사전 자료형은 체계적으로 정리된 자료들을 효율적으로 다룬다.
tweet = {
"사용자" : "길동",
"문장" : "데이터 과학 멋져요!",
"리트윗 수" : 100,
"해시태그" : ["#데이터", "#과학", "#데이터과학", "#멋져요"]
}
tweet
{'사용자': '길동', '문장': '데이터 과학 멋져요!', '리트윗 수': 100, '해시태그': ['#데이터', '#과학', '#데이터과학', '#멋져요']}
keys
, values
, items
¶키만 또는 값만 따로따로 모아서 확인 및 활용할 수 있다.
tweet_keys = tweet.keys()
tweet_keys
dict_keys(['사용자', '문장', '리트윗 수', '해시태그'])
tweet_values= tweet.values()
tweet_values
dict_values(['길동', '데이터 과학 멋져요!', 100, ['#데이터', '#과학', '#데이터과학', '#멋져요']])
사전 자료형에 포함된 키와 값으로 이루어진 쌍들을 일종의 리스트로 확인할 수도 있다.
tweet_items = tweet.items()
tweet_items
dict_items([('사용자', '길동'), ('문장', '데이터 과학 멋져요!'), ('리트윗 수', 100), ('해시태그', ['#데이터', '#과학', '#데이터과학', '#멋져요'])])
dict_keys
, dict_values
, dict_items
는
사전 자료형과 관련된 새로운 자료형들이지만,
여기서는 자세히 알 필요가 없다.
다만, 아래와 같이 항목들을 for
반복문을 이용하여 접근할 수
있다는 점은 기억해야 한다.
for item in tweet_keys:
print(item)
사용자 문장 리트윗 수 해시태그
또는 아래와 같이 리스트로 형변환해서 사용할 수도 있다.
list(tweet_items)
[('사용자', '길동'), ('문장', '데이터 과학 멋져요!'), ('리트윗 수', 100), ('해시태그', ['#데이터', '#과학', '#데이터과학', '#멋져요'])]
in
연산자 처리속도¶리스트에서 사용되는 in
연산자와 사전에서 사용되는 in
연산자는 내부적으로 서로 다르게 작동한다.
여기서는 처리속도 관련해서만 설명한다.
in
연산자 검색 속도: 평균적으로 사용되는 리스트의 길이에 비례in
연산자 검색 속도: 평균적으로 사전의 길이에 상관없음. 다만 최악의 경우 길이에 비례.자세한 내용은 시간 복잡도를 참조할 수 있다.
defaultdict
클래스 활용¶문서에서 단어 빈도수를 확인하고자 할 때 보통 사전 자료형을 이용하며, 빈 사전을 만든 다음에 단어를 키로, 빈도수를 값으로 항목을 추가한다.
if ... else...
조건문 활용¶단어가 기존에 없으면 새로운 키-값 쌍을 생성하여 추가하고, 기존에 있으면 해당 키값에 1을 더한다.
document = ["data", "science", "from", "scratch", "data", "from"]
word_counts = {}
for word in document: # 단어가 키로 사용되었는지 여부 확인
if word in word_counts: # 이미 추가된 단어가 다시 나올 때
word_counts[word] += 1
else: # 새 단어를 추가할 때
word_counts[word] = 1
word_counts
{'data': 2, 'science': 1, 'from': 2, 'scratch': 1}
try ... except
예외 처리 활용¶사전에 새로운 키-값 항목을 추가할 때 발생할 수 있는 오류에 대비하여 처리한다.
word_counts = {}
for word in document:
try: # 이미 추가된 단어가 다시 나올 때
word_counts[word] += 1
except KeyError: # 새 단어 추가과정에서 오류가 발생할 때
word_counts[word] = 1
word_counts
{'data': 2, 'science': 1, 'from': 2, 'scratch': 1}
get
메소드 활용¶get
메소드의 둘째 인자를 활용할 수 있다.
word_counts = {}
for word in document:
previous_count = word_counts.get(word, 0) # 새 단어가 추가될 때 0을 사용
word_counts[word] = previous_count + 1
word_counts
{'data': 2, 'science': 1, 'from': 2, 'scratch': 1}
defaultdict
클래스 활용¶앞서 설명한 세 가지 방식 모두 약간 복잡하다.
하지만 collections
모듈에서 정의된 defaultdict
클래스를 활용하면
단어가 이미 나왔었는지 여부를 구분하지 않으면서
일을 진행할 수 있다.
from collections import defaultdict
word_counts = defaultdict(int)
for word in document:
word_counts[word] += 1
word_counts
defaultdict(int, {'data': 2, 'science': 1, 'from': 2, 'scratch': 1})
defaultdict(int)
의 의미는 다음과 같다.
int
), 즉 정수형 사용.defaultdict(list)
활용¶list
) 자료형[]
)가 기본값으로 지정된다.[]
으로 초기화 되어 있기에 새로운 키를 추가해도 오류가 나지 않는다.append
메소드 활용dd_list = defaultdict(list)
dd_list[2].append(1)
print(dd_list)
defaultdict(<class 'list'>, {2: [1]})
type(dd_list)
collections.defaultdict
defaultdict(dict)
활용¶dict
) 자료형{}
)이 기본값으로 지정된다.{}
로 초기화 되어 있기에 새로운 키를 추가해도 오류가 나지 않는다.[]
) 활용아래와 같이 사전 자료형을 값으로 갖는 사전을 생성할 수 있다.
dd_dict = defaultdict(dict)
dd_dict["홍길동"]["성별"] = "남성"
dd_dict["홍길동"]["생년월일"] = "2000.03.08"
dd_dict["홍길동"]["전공"] = "컴퓨터공학"
dd_dict["성춘향"]["성별"] = "여성"
dd_dict["성춘향"]["생년월일"] = "2001.08.03"
dd_dict["성춘향"]["전공"] = "응용수학"
for student in dd_dict:
print(student, dd_dict[student], sep=':')
홍길동:{'성별': '남성', '생년월일': '2000.03.08', '전공': '컴퓨터공학'} 성춘향:{'성별': '여성', '생년월일': '2001.08.03', '전공': '응용수학'}
defaultdict(lambda: value)
활용¶value
에 지정된 자료형 사용value
로 사용된 값을 기본값으로 사용dd_pair = defaultdict(lambda: [0, 0]) # 길이가 2인 리스트를 값으로 활용. 초기값은 모두 0.
dd_pair[2][1] = 1 # 키 2에 해당하는 값을 [0, 1]로 지정
dd_pair
defaultdict(<function __main__.<lambda>()>, {2: [0, 1]})
주의:
dd_pair[2]
원래 [0, 0]
임. dd_pair[2][1] = 1
은 [0, 0][1] = 1
에 해당함.문자열, 리스트, 튜플, 사전 자료형 등 여러 개의 값을 모둠으로 갖는 값으로부터
항목들의 빈도수를 측정하여 담은 defaultdict
자료형과 유사하지만
보다 강력한 기능을 가진 Counter
자료형을 반환한다.
from collections import Counter
num_count = Counter([0, 1, 2, 0, 2])
num_count
Counter({0: 2, 1: 1, 2: 2})
앞서 여러 방식으로 다루었던 document
에 사용된 단어들의 빈도수를 아래와 같이 쉽게 구할 수 있다.
document
['data', 'science', 'from', 'scratch', 'data', 'from']
word_counts = Counter(document)
word_counts
Counter({'data': 2, 'science': 1, 'from': 2, 'scratch': 1})
most_common
메소드¶Counter
자료형의 메소드 중에 most_common
메소드가 유용하게 사용되며,
빈도수를 기준으로 내림차순으로 정렬해준다.
예를 들어, 빈도수가 가장 높은 항목 세 개를 내림차순으로 보려주려면 다음과 같이 실행한다.
for item in word_counts.most_common(3):
print(item)
('data', 2) ('from', 2) ('science', 1)
for word, count in word_counts.most_common(3):
print(word, count)
data 2 from 2 science 1
set
자료형은 집합에 해당하는 자료형이며, 수학에서 배운 집합 개념과 동일하다.
primes_below_10 = {2, 3, 7, 5, 7, 3}
primes_below_10
{2, 3, 5, 7}
원소의 개수는 len
함수를 이용하여 확인한다.
len(primes_below_10)
4
공집합은 set()
으로 생성하며, 원소 추가는 add
메소드를 활용한다.
s = set()
s.add(1)
s.add(2)
s.add(2)
print(s)
{1, 2}
원소의 포함여부는 in
연산자를 활용하여 확인한다.
2 in s
True
3 in s
False
리스트에 중복으로 포함된 항목을 쉽게 제거할 수 있다.
item_list = [1, 2, 3, 1, 2, 3]
item_set = set(item_list)
distinct_item_list = list(item_set)
print(distinct_item_list)
[1, 2, 3]
리스트에 중복으로 포함된 항목이 존재하는가를 쉽게 판단할 수 있다. 예를 들어, 아래 함수는 중복 함수의 포함여부를 판단해준다.
def has_duplicates(t):
return len(set(t)) < len(t)
has_duplicates(item_list)
True
길이가 매우 긴 리스트를 대상으로 항목의 존재여부를 판단할 때 집합 자료형으로 형변환을 하면 매우 빠르게 해결할 수 있다.
hundreds_of_other_words = [] # 매우 긴 리스트라 상상한다.
stopwords_list = ["a", "an", "at"] \
+ hundreds_of_other_words + ["yet", "you"]
print("zip" in stopwords_list) # 확인 과정이 느리다.
stopwords_set = set(stopwords_list)
print("zip" in stopwords_set) # 매우 빠르게 확인한다.
False False
부분집합 관계를 이용할 수 있다. 예를 들어, 아래 함수는 첫째 인자의 리스트에 포함된 모든 원소가, 둘째 인자의 리스트에 항목으로 포하되는지 여부를 판단한다.
주의: <=
연산자는 집합을 대상으로 할 경우 부분집합 관계를 결정한다.
def sublist(list1, list2):
return set(list1) <= set(list2)
sublist(item_list, distinct_item_list)
True
if
조건문 활용¶이프(if
) 조건문을 이용하여 상황에 따른 프로그램을 수행하도록 하는 것은 여느 프로그래밍 언어와 유사하다.
주의:
:
) 사용에 주의해야 한다.{}
)는 사용하지 않는다.if 1 > 2:
message = "1이 2보다 크기를 바라지만..."
elif 1 > 3:
message = "elif는 'else if'의 줄임말임."
else:
message = "앞서 언급된 조건이 모두 적용되지 않을 때 사용"
print(message)
앞서 언급된 조건이 모두 적용되지 않을 때 사용
if
조건문¶간단한 한 줄 조건문을 종종 사용할 것이다.
x = 10
parity = "짝수" if x % 2 == 0 else "홀수"
print(parity)
짝수
while
반복문 활용¶여느 프로그래밍 언어에서처럼 while
반복문도 제공된다.
역시 콜론과 들여쓰기에 주의한다.
x = 0
while x < 10:
print(f"{x}는(은) 10보다 작다.")
x += 1
0는(은) 10보다 작다. 1는(은) 10보다 작다. 2는(은) 10보다 작다. 3는(은) 10보다 작다. 4는(은) 10보다 작다. 5는(은) 10보다 작다. 6는(은) 10보다 작다. 7는(은) 10보다 작다. 8는(은) 10보다 작다. 9는(은) 10보다 작다.
for ... in ...
반복문 활용¶while
반복문 보다 for ... in ...
반복문을 보다 많이 사용할 것이다.
특히, range
함수와 찰떡궁합이라서 활용도가 매우 높다.
range(10)
range(0, 10)
for x in range(10):
# x 는 0부터 9까지 움직이며 가리킨다.
print(f"{x}는 10보다 작아요.")
0는 10보다 작아요. 1는 10보다 작아요. 2는 10보다 작아요. 3는 10보다 작아요. 4는 10보다 작아요. 5는 10보다 작아요. 6는 10보다 작아요. 7는 10보다 작아요. 8는 10보다 작아요. 9는 10보다 작아요.
리스트의 슬라이싱에서 사용하는 구간의 처음과 끝, 스텝(step)을 이용할 수도 있다.
for item in range(5,10):
# 5부터 시작한다.
print(item)
5 6 7 8 9
for item in range(1,10, 2):
# 2계단씩 건너 뛴다.
print(item)
1 3 5 7 9
continue
와 break
¶for ... in ...
반복문을 이용하여 좀 더 복잡한 알고리즘을 구성하려면 continue
와 break
를 잘 활용하면 된다.
for x in range(10):
if x == 3:
continue # 반복이 다음 단계로 넘어 간다.
# 즉, x가 바로 다음 값으로 변하고 아래 명령문은 실행하지 않는다.
# 따라서 x = 3 인 경우를 건너뛴다.
if x == 5:
break # 이 명령문을 감싸는 for 반복문을 바로 종료한다.
print(x)
0 1 2 4
bool
) 자료형: 진리값¶파이썬에서 사용되는 진리값은 모두 대문자로 시작한다: True
(참), False
(거짓)
one_is_less_than_two = 1 < 2
true_equals_false = True == False
print(one_is_less_than_two)
True
and
, or
, not
¶논리합(and
), 논리곱(or
), 부정(not
) 연산자는 진리값을 대상으로 하며
여느 프로그래밍 언어에서 배운 내용과 동일하게 작동한다.
print(one_is_less_than_two and true_equals_false)
print(one_is_less_than_two or true_equals_false)
print(not true_equals_false)
False True True
None
값¶C, Java 언어에서 사용되는 널(null) 값에 해당하는 것이 파이썬에서는 None
이며,
다른 언어에서와의 차이점을 None
도 하나의 값이라는 점이다.
즉, 변수에 저장하고 다른 값과 비교할 수 있다.
x = None
print(x == None)
True
아래와 같이 assert
키워드를 이용하여 원하는 결과가 나오는지를 테스팅할 수 있다.
assert x is None
주장이 참이면 아무 것도 보여주지 않는다. 하지만 주장이 틀리면 오류를 발생시킨다.
assert x is 1
--------------------------------------------------------------------------- AssertionError Traceback (most recent call last) <ipython-input-59-787561859c79> in <module> ----> 1 assert x is 1 AssertionError:
예외 처리를 이용하여 주장이 왜 틀렸는지 등을 보여줄 수 있다.
assert x is 1, "x는 None이 할당되어 있다."
--------------------------------------------------------------------------- AssertionError Traceback (most recent call last) <ipython-input-60-44728a1b0677> in <module> ----> 1 assert x is 1, "x는 None이 할당되어 있다." AssertionError: x는 None이 할당되어 있다.
주의: assert
에 대해서는 파이썬 속성 강좌 2부에서 좀 더 다룬다.
False
)으로 간주되는 값¶아래 값들은 상황에 따라 부울 자료형의 거짓(False
)으로 간주된다.
None
[]
(빈 리스트){}
(빈 사전)""
(빈 문자열)set()
(공집합)0
(정수 0)0.0
(실수 0.0)나머지 값들의 대부분은 상황에 따라 부울 자료형의 참(True
)으로 간주된다.
예제 1: 빈 문자열을 반환하는 함수의 반환값은 거짓으로 취급됨.
def some_function_that_returns_a_string():
return ""
s = some_function_that_returns_a_string()
if s:
first_char = s[0]
else:
first_char = ""
first_char == ""
True
주의: ==
는 양측의 값의 동일성을 결정한다.
and
연산자 작동방식¶위 코드는 아래와 같이 한 줄로 작성할 수 있다.
first_char = s and s[0]
이유는 and
연산자의 작동방식에 찾을 수 있다.
s
가 참이면 s[0]
의 참, 거짓을 판단.s
가 거짓이면 False
로 판단하며 s[0]
은 아예 확인조차 하지 않음.or
연산자 작동방식¶A or B
는 다음처럼 작동한다.
A
가 참이면 True
로 판단하며, B
는 아예 확인조자 하지 않음.A
가 거짓이면 B
로 판단.예제 2: 아래 두 명령문은 동일한 일을 수행한다.
safe_x = x or 0
safe_x = x if x is not None else 0
all
과 any
함수¶리스트에 대해
all
함수: 모든 항목이 참이면 True
반환any
함수: 항목 하나라도 참이면 True
반환all([True, 1, {3}]) # True, all are truthy
True
all([True, 1, {}]) # False, {} is falsy
False
any([True, 1, {}]) # True, True is truthy
True
all([]) # True, no falsy elements in the list
True
any([]) # False, no truthy elements in the list
False