책 '파이썬 코딩의 기술'에서 2장 내용인 리스트와 딕셔너리에 대해 다뤄보도록 하겠다. 슬라이드, 슬라이싱에 대해선 정리하지 않을 예정이다. 다룰 항목은 다음과 같다.
- 언패킹
- key
- dic
- get
- setdefault
- defaultdic
1. 언패킹
* (별표식)으로 값들을 다음과 같이 언패킹 할 수 있다. 이 *식은 리스트 인스턴스가 된다.
def my_function():
...
return a, b, c, d, e
#언패킹 no 사용
a, b, c, d, e = my_function
#언패킹 사용 예 1: a,b만 필요할 때
a, b, * = my_function
#언패킹 사용 예 2: 맨 앞뒤 return값만 필요할 때
a, *bdc, e = my_function
별표식이 항상 리스트를 만들기 때문에 너무 크면 메모리에 올라가지 않을 수 있음에 주의해야 한다.
2. key 인자
내가 정의한 객체에서 특정 정렬 조건을 적용하고 싶을 때 sort 내에서 key를 사용한다.
list_ex = [ ... ]
# 대소문자 구분 안 한 문자열 정렬 예시
list_ex.sort(key = lambda x: x.lower)
key 값으로 2개를 쓰고 싶다면 아래와 같이 튜플로 적용할 수 있다. (key1 순으로 정렬 후 key2순으로 정렬하고 싶을 때)
list_ex.sort(key = lambda x:(x.key1, x.key2))
기본 default는 오름차순 정렬이다. 내림차순 정렬을 원할 때는 아래와 같이 1) reverse를 사용하거나 2) 상수일 경우는 - 부호를 붙여주는 형태도 가능하다.
## 내림차순 정렬을 하고 싶을 때
list_ex.sort(key = lambda x:(x.key1, x.key2), reverse = True)
## key로 받는 인자가 숫자일 때
list_ex.sort(key = lambda x: -x.key1)
## key1로 오름차순 후 key2로 내림차순을 하고 싶을 때
list_ex.sort(key= lmabda x:x.key2, reverse = True)
list_ex.sort(key = lambda x:x.key1)
3. 딕셔너리 주의점
책을 읽기 전까지 몰랐다. 파이썬 3.5 이전에는 딕셔너리 내 이터레이션 순서가 원소가 삽입된 순서와 일치하지 않았다는 사실을! 다행히 3.7 버전 이후부터는 딕셔너리 인스턴스 내 키를 삽입한 순서대로 돌려받는 게 default다.
get을 이용하는 방법
딕셔너리 내부를 살펴볼 때 나는 보통 다음과 같이 in을 사용했다. 아래 코드에서 key가 없을 때 keyerror를 발생시켜야 하는데, 이 과정에서 코드가 깔끔하지 않게 된다.
my_dic = {}
...
#in
if key in my_dic:
print(my_dic[key])
##in이 가독성이 안좋은 예시
try:
print(my_dic[key])
except KeyError:
my_dic[key]=1
print('keyerror occurs')
get을 사용한다면 아래와 같이 코드가 깔끔해진다.
#dic get사용 + 왈러스 연산자 예시
if (tmp := my_dic.get(key) is None:
my_dic[key] = 1
setdefault
setdefault는 key를 딕셔너리에서 가져오게끔 하는데, key가 딕셔너리 안에 없을 경우 두 번째 인자를 디폴트 값으로 반환한다. 문제는 아래 코드의 2번째 예제처럼 setdefault의 return값이 전달되지 않았을 때 값이 직접 딕셔너리에 대입되는 것이다. 심지어 값을 get 해오는 건데 set이 붙는 이름도 이상하다!
#Defaultdict
tmp = my_dic.setdefault(key, 1)
#### my_dic에 key가 없다면 tmp = 1
#### my_dic에 key가 있다면 tmp = my_dic[key]
#2번째 에제
value = []
my_dic.setdefault(key, value)
print(my_dic) # {key : []}
value.append(1)
print(my_dic) # {key : [1]}
defaultdict
setdefault를 써야 할 경우 대부분은 defaultdict를 쓰면 해결이 된다. 심지어 새로운 dic를 만들고 싶을 때 클래스 내에 defaultdict를 사용하는 것이 더 좋다. setdefault는 key의 존재 유무에 상관없이 항상 default인스턴스를 만들기 때문이다.
from collections import defaultdict
my_dic = defaultdict(int) # default값이 int형인 딕셔너리 생성
print(my_dic[key]) # --> {key : 0} #위에서 default를 int로 설정했기 때문에 0이 default다
## 딕셔너리 형태의 클래스를 만들 때
class MyDic:
def __init__(self):
self.data =.defaultdict(set)
def add(self, key, value):
self.data[key].add(value)
__missing__
dic의 특별 메서드로 __missing__을 구현할 수 있다. defaultdict 생성자에 함수가 들어갈 경우, 함수 인자는 받을 수 없다. key가 없을 때 open_picture라는 함수를 작동시키는 딕셔너리 클래스를 아래와 같이 구현할 수 있다.
#내장함수 __missing__이 없을 때
def open_picture(path):
try:
return open(path, 'a+b') # a+는 처음부터 읽는다는 건데, 파일이 없을땐 생성도 해준다
except OSError:
raise
my_dic = defaultdic(open_picture) # 에고 path를 전달하지 못하는데! --> error 발생!
handle = my_dic[path]
handle.seek(0)
...
#내장함수 __missing__이 있는 custom dict를 만든다면?
class MyDic(dict):
def __missing__(self, key):
value = open_picture(path)
self[key] = value
return value
my_dic = MyDic()
handle = my_dic[path]
handle.seek(0)
....
이 방법이 setdefault보다 좋은 이유는 뭘까? setdefault는 key값이 있어도 계속 호출이 된다는 것이고, __missing__은 key가 없을 때만 실행된다는 것이 큰 차이다.
'python > 파이썬 코딩의 기술' 카테고리의 다른 글
파이썬 코딩의 기술 리뷰 - 클래스, 인터페이스 (0) | 2022.01.16 |
---|---|
파이썬 코딩의 기술 리뷰- 동시성과 병렬성 1 (2) | 2022.01.10 |
파이썬 코딩의 기술 - 컴프리헨션, 제너레이터 (0) | 2022.01.09 |
파이썬 코딩의 기술 리뷰 - 함수 (0) | 2021.12.19 |
파이썬 코딩의 기술 리뷰 - self와 cls, bytes와 str, f-문자열, 왈러스 연산자 (2) | 2021.12.12 |