관련글 ▼
[인프런 리프 2기] 06. 파이썬 중급 과정 2주차(4) 데이터 모델-1
[인프런 리프 2기] 07. 파이썬 중급 과정 2주차(5) 데이터 모델-2,3
[인프런 리프 2기] 08. 파이썬 중급 과정 3주차(1) 시퀀스-1,2
시퀀스 타입 중 tuple과 list 심화를 했다면 드디어 이번에는 dict 심화다.
key-value 쌍을 저장하는 데이터 구조 형이다. key는 hash 함수로 보내져서 산수연산을 수행한다. 결과값(보통 hash 값, 혹은 hash라고 불림)은 해시 테이블에서 key-value 쌍의 인덱스이다. (출처)
간단히 말하면 key에 value를 저장하는 구조로 python은 강력한 hashtable로 만들어진 언어라고 소개되곤 한다. dict 형에서 key는 주민등록번호같은 고유한 값이기 때문에 중복되면 안된다.
** 구글이나 아마존 등에서 개발자를 구하는 면접에서 hastable에 키가 중복되면 어떻게 처리하느냐고 많이 묻는다(고한다).
파이썬에는 dict가 있기때문에 hash를 직접 구현할 필요가 없다.
왜 사용할까? key 값의 연산 결과에 따라 자료에 직접 접근이 가능한 구조이기때문에 사용한다.
print(__builtins__.__dict__)
hash() : key를 함수를 이용해서 hashing한 다음 해시 주소를 알고, 해당 key에 대한 value를 구한다.
t1 = (10, 20, (30, 40, 50))
t2 = (10, 20, [30, 40, 50])
print(hash(t1))
print(hash(t2))
hash함수를 이용해 hash값을 구하려면 해당 객체의 자료가 immutable이어야 한다. 수정도, 삭제도 불가능한 tuple 같은 형식이어야만 hash값을 구할 수 있다.
t2은 가변형 컨테이너인 list가 들어가므로 unhashable type : list 라는 TypeError가 발생한다.
setdefault를 이용하면 tuple 객체를 dict 객체로 바꿀 수 있다. 속도가 빠르기 때문에 대용량 데이터를 다룰 때 사용하기 좋다.
source = (('k1', 'val1'),
('k1', 'val2'),
('k2', 'val3'),
('k2', 'val4'),
('k2', 'val5'))
nw_dict1 = {}
nw_dict2 = {}
source라는 tuple 자료를 갖는 tuple 객체를 만들었다. 여기서 새로운 dict 객체를 만드는 방법은 두가지가 있다.
1. Setdefault를 사용하지 않을 경우
for k, v in source:
if k in nw_dict1:
nw_dict1[k].append(v)
else:
nw_dict1[k] = [v]
2. Setdefault를 사용할 경우
for k, v in source:
nw_dict2.setdefault(k,[]).append(v)
※ 주의할 점
nw_dict3 = {k: v for k, v in source}
이렇게 입력하면 1,2번과 동일한 값이 나올 것 같지만 오산이다. 같은 key를 값는 value들이 있기 때문에 value끼리 중첩되어서 최종적으로 print(nw_dict3)을 출력해보면 { 'key1' : 'value2', 'key2' : 'value5' } 만 나온다.
n = {'a': 2, 'b': 4}
n[c] = 12 # 없는 키는 추가한다.
n[a] = 3 # 있는 키는 value를 바꾼다.
print(a)
mapping proxy type 을 지원 받으면 read only를 만들 수 있다. 중요한 값이라 절대 수정되면 안될 경우로 가정하고 dict 객체를 read-only로 해버리면 효율적으로 사용할 수 있다.
from types import MappingProxyType
d = {'key1' : 'value1', 'key2' : 'value2'}
d_frozen = MappingProxyType(d)
** frozen은 해외에서 read only 형을 만들 때 자주 쓰는 변수명이라고 한다.
새로운 변수를 선언하고 MappingProxyType()에 앞서 선언한 dict 객체를 넣어주면 read-only가 된다.
d와 d_frozen의 hash value를 구하려고 하면 unhashable type이라는 오류가 난다.
왜? d는 가변 'dict'이고 d_frozen은 불변 'dict'이니까. dict객체는 read-only든 아니든 hash value를 구할 수 없다.
반면 d와 d_frozen에 수정을 가하려고 하면 d_frozen은 'mappingproxy' object does not support item assignment 라는 오류가 나면서 되지 않는다.
왜? d_frozen은 읽기만 가능한(read-only) 객체로 선언했기 때문이다. writing이 될리가 없다.
집합 자료형은 dict와 유사하다. list처럼 만들고 괄호의 모양만 바꾸면 된다 ( [ ] -> { } ). 하지만, list처럼 원소의 중복을 허용하지 않는다.
s1 = {'Mango', 'Orange', 'Mango', 'Kiwi', 'Kiwi'}
print(s1)
s2 = set(['Mango', 'Orange', 'Mango', 'Kiwi', 'Kiwi'])
print(s2)
Mango와 kiwi는 중첨되기 때문에 print해보면 Mango, Orange, Kiwi라고만 출력된다.
s3 = {3}
s4 = {}
print(type(s3))
print(type(s4))
두 객체를 type() 함수를 이용해서 자료형을 알아보고자 하면 s3은 set인 반면 s4는 dict라고 나온다. 따라서, { } 안에 원소가 하나라도 있어야 set으로 선언되며 하나도 없을 경우에는 dict로 선언된다.
s5 = set()
원소가 하나도 없는 set을 선언하고 싶을때는 set() 를 이용한다.
s6 = frozenset(s1)
set을 read-only로 만들고 싶을 때는 frozenset() 을 사용한다.
s1.add ('melon')
set에 원소를 추가하고 싶으면 add attribute를 사용하면 된다. 참고로 해당 attribute는 set에서만 사용가능하기 때문에 dict에서는 add를써도 key 와 value가 추가되지 않는다.
왜? 둘다 중괄호를 사용하는 자료형이지만 set은 { 원소1, 원소2, 원소3, ... 원소n }으로 선언하고 dict는 { key1 : value2, key2 : value2, ... keyN : valueN)으로 선언하기 때문이다.
파이썬은 파이썬 인터프리터가 바이트코드를 어셈블리해서 실행하는데 dis 모듈을 이용하면 바이트코드를 역으로 어셈플리할 수 있다.
from dis import dis
print('------')
print(dis('{10}')) # 스텝이 3단계
print('------')
print(dis('set([10])')) #스텝이 5단계
dis 모듈 : 바이트코드를 역으로 어셈블리하는, 즉 모인 걸 푸는 모듈.
같은 10이라는 숫자형 자료를 가진 시쿼스탕비이지만 역어셈블리된 바이트코드를 보면 실행되는 스텝의 수가 다르다는 걸 알 수 있다. 따라서, set으로 직접 선언하기보다 {} 중괄호를 사용하는 게 속도면에서 낫다.
print({chr(i) for i in range(0,256)})
0~255사이의 숫자를 i에 대입해서 나온 값의 집합이라는 의미다.
from unicodedata import name
print({name(chr(i), '') for i in range(0,256)})
name 모듈을 import하게 될 경우, chr화된 unicode의 이름을 가져온다.
[인프런 리프 2기] 10. 파이썬 중급 과정 3주차(4) 일급함수-3,4 (0) | 2021.03.28 |
---|---|
[인프런 리프 2기] 10. 파이썬 중급 과정 3주차(3) 일급함수-1,2 (0) | 2021.03.27 |
[인프런 리프 2기] 08. 파이썬 중급 과정 3주차(1) 시퀀스-1,2 (0) | 2021.03.25 |
[인프런 리프 2기] 07. 파이썬 중급 과정 2주차(5) 데이터 모델-2,3 (0) | 2021.03.21 |
[인프런 리프 2기] 06. 파이썬 중급 과정 2주차(4) 데이터 모델-1 (0) | 2021.03.21 |
댓글 영역