상세 컨텐츠

본문 제목

[인프런 리프 2기] 09. 파이썬 중급 과정 3주차(2) 시퀀스-3,4

경험/2021 인프런리프2기

by mizu-umi 2021. 3. 27. 17:31

본문

728x90

관련글 ▼

[인프런 리프 2기] 06. 파이썬 중급 과정 2주차(4) 데이터 모델-1

[인프런 리프 2기] 07. 파이썬 중급 과정 2주차(5) 데이터 모델-2,3

[인프런 리프 2기] 08. 파이썬 중급 과정 3주차(1) 시퀀스-1,2

 


 

 

파이썬 시퀀스(3)

  • 해시 테이블(Hashtable)
  • Dict 생성 고급예제
  • Setdefault 사용법

 

시퀀스 타입 중 tuple과 list 심화를 했다면 드디어 이번에는 dict 심화다.

 

  • tuple to list : .tolist를 이용하면 쉽게 바꿀 수 있다.
  • tuple to dict : key를 하나로 통합해야해서 list만큼 쉽지는 않다.

해시 테이블(Hashtable)이란?

key-value 쌍을 저장하는 데이터 구조 형이다. key는 hash 함수로 보내져서 산수연산을 수행한다. 결과값(보통 hash 값, 혹은 hash라고 불림)은 해시 테이블에서 key-value 쌍의 인덱스이다. (출처)

간단히 말하면 key에 value를 저장하는 구조로 python은 강력한 hashtable로 만들어진 언어라고 소개되곤 한다. dict 형에서 key는 주민등록번호같은 고유한 값이기 때문에 중복되면 안된다. 

 

** 구글이나 아마존 등에서 개발자를 구하는 면접에서 hastable에 키가 중복되면 어떻게 처리하느냐고 많이 묻는다(고한다).

 

파이썬에는 dict가 있기때문에 hash를 직접 구현할 필요가 없다. 

 

왜 사용할까? key 값의 연산 결과에 따라 자료에 직접 접근이 가능한 구조이기때문에 사용한다.

 

print(__builtins__.__dict__) 
  • __builtin__ 즉파이썬에 내장된(built-in) class를 dict 구조로 출력할 수 있다. 출력된 결과물을 보면 {'hash' : <built-in function hash } 즉 hash(key)라는 함수(value)가 있음을 알 수 있다. 

 

해시값구하기 Hashing Function

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

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]

 

  • 기존의 for-loop를 사용해서 source에 있는 값을 nw_dict1에 넣어주면 된다.

2. Setdefault를 사용할 경우

for k, v in source:
    nw_dict2.setdefault(k,[]).append(v) 
  • 1번의 방법보다 코드가 훨씬 짧아지고 간단명료하게 tuple 자료를 dict 객체에 넣을 수 있다.

 

※ 주의할 점

nw_dict3 = {k: v for k, v in source}

이렇게 입력하면 1,2번과 동일한 값이 나올 것 같지만 오산이다. 같은 key를 값는 value들이 있기 때문에 value끼리 중첩되어서 최종적으로 print(nw_dict3)을 출력해보면 { 'key1' : 'value2', 'key2' : 'value5' } 만 나온다.

 


파이썬 시퀀스(3)

  • 해시 테이블(Hashtable)
  • Immutable Dict 생성
  • 지능형 Set
  • Set 선언 최적화

 

Dict 자료형의 기본적인 수정 방법

n = {'a': 2, 'b': 4}
n[c] = 12 # 없는 키는 추가한다.
n[a] = 3 # 있는 키는 value를 바꾼다.
print(a)

 

불변 딕셔너리 Immutable Dict

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이 될리가 없다.

 

집합 자료형 Set Type

집합 자료형은 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으로 직접 선언하기보다 {} 중괄호를 사용하는 게 속도면에서 낫다.

 

 

지능형 집합 Comprehending 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의 이름을 가져온다.


< 강의 출처 - 인프런 우리를 위한 프로그래밍 파이썬 중급 (Inflearn Original) 

728x90
반응형

관련글 더보기

댓글 영역