이 글은 슬기로운 파이썬 트릭을 읽고 핵심만 빠르게 정리한 글이다.
6, 7장에서 정리할 내용이 적어 한 글에 압축하여 포스팅한다.
6장. 반복과 이터레이션
6장 앞 부분은 다음 파트들로 이루어져 있다.
- 6.1. 파이썬다운 반복문 작성하기
- 6.2. 리스트 컴프리핸션 이해하기
- 6.3. 리스트 분할 트릭과 스시 연산자
- 6.4. 아름다운 이터레이터
- 6.5. 제너레이터는 단순화된 이터레이터다.
- 6.6. 제너레이터 표현식
이 파트들은 너무 간단한 파이썬 내용이거나, 이전에 공부하며 기록했던 내용이라 그냥 과감히 넘어간다.
이터레이터, 제너레이터 관련해 이전에 공부한 기록은 파이썬 클린 코드 1 - 파이썬스러운 코딩을 파이썬 문법 컨셉에 가면 볼 수 있다.
6.7. 이터레이터 체인
이터레이터 체인이란 아래 예와 같은 것이다.
def intergers():
for i in range(1, 9):
yield i
def squared(seq):
for i in seq:
yield i * i
>>> chain = squared(integers())
>>> list(chain)
[1, 4, 9, 16, 25, 36, 49, 64]
chain
은 한 방향으로 흐르는 일련의 파이프라인을 갖고있다.- 위 구조에서 파이프라인은
integers
를 거쳐squared
로, 그리고 마지막에list
로 실행된다. - 파이프라인의 좋은 점은 단계 별로 할 일을 분리하여 처리할 수 있다는 것이다.
- 또한 데이터 처리가 '한 번에 한 항목씩' 이뤄진다는 것이다. 즉 체인 처리 단계 사이에 버퍼링이 없다.
- 체인에 새로운 블록을 추가시키고 싶을 때 다음과 같이 쉽게 붙일 수 있다.
def negated(seq):
for i in seq:
yield -i
>>> chain = negated(squared(integers()))
>>> list(chain)
[-1, -4, -9, -16, -25, -36, -49, -64]
7장. 딕셔너리 트릭
7.1. 딕셔너리 기본 값
name_for_userid = {
382: "Alice"
}
# 지양해야 되는 코드
def greeting(userid):
if userid in name_for_userid:
return f"Hi {name_for_userid[userid]}"
else:
reutrn f"Hi There"
# 더 나은 코드
def greeting(userid):
return f"Hi, {d.get(userid, 'There')}"
- 딕셔너리에 없는 Key 값을 처리해야 할 땐,
get
메서드나collections.defaultdict
을 사용하자.
7.2. 재미있고 효과도 좋은 딕셔너리 정렬
>>> xs = {'a': 4, 'c': 2, 'b': 3, 'd': 1}
>>> sorted(xs)
['a', 'b', 'c', 'd']
>>> sorted(xs.items())
[('a', 4), ('b', 3), ('c', 2), ('d', 1)]
>>> sorted(xs.items(), key=lambda x: x[1])
[('d', 1), ('c', 2), ('b', 3), ('a', 4)]
>>> sorted(xs.items(), key=lambda x: x[1], reverse=True)
[('a', 4), ('b', 3), ('c', 2), ('d', 1)]
sorted
의key
와reverse
파라미터의 인자 값을 활용하여 효과적으로 정렬할 수 있다.key
에는callable
한 객체(즉 함수나__call__
메소드를 가진 클래스)를 주면 된다.- 이 객체의 반환 값을 기준으로 모든 요소를 비교한다.
reversed
에는bool
값 (즉True
나False
) 를 주면 된다. 오름차순, 내림차순을 정할 수 있다.
7.3. 딕셔너리로 switch/case
문 모방하기
def dispatch_dict(operator, x, y):
return {
"add": lambda: x + y,
"sub": lambda: x - y,
"mul": lambda: x * y,
"div": lambda: x / y
}.get(operator, lambda: None)()
>>> dispatch_dict("add", 1, 2)
3
>>> dispatch_dict("root", 1, 2)
None
- 파이썬에는
switch/case
문이 문법적으로 없다. - 위처럼 코딩하면 긴 if 체인을 다루지 않아도 되고, 좀 더 파이써닉하게 사용할 수 있다.
- 실제 프로덕션에서 쓸 때는, 딕셔너리를 따로 상수로 빼놓아 한 번만 만들어놓아야 좀 더 이상적이다.
7.4. 딕셔너리 표현식의 특이점
>>> {True: 'yes', 1: 'no', 1.0: 'maybe'}
{True: 'maybe'}
True
,1
,1.0
은 모두 같은 것으로 취급된다. (True == 1 == 1.0
의 값은True
다.)- 파이썬은
bool
을int
의 서브 클래스로 취급한다. - 딕셔너리에 기존 키 값에 새로운 값이 업데이트 될 때, 값만 업데이트 하고 키 값 자체는 업데이트 하지 않는다.
(그래서 위 예제에서 키가1.0
이 아니라 여전히True
다.) - 나도 이번에 공부하며 새로알게 된 거라 신기했음.
7.5. 딕셔너리를 병합하는 많은 방법
# update() 메서드 사용
>>> xs = {'a': 1, 'b': 2}
>>> ys = {'b': 3, 'c': 4}
>>> xs.update(ys)
>>> xs
{'a': 1, 'b': 3, 'c': 4}
# {**dict1, **dict2} 사용
>>> xs = {'a': 1, 'b': 2}
>>> {**xs, **ys}
{'a': 1, 'b': 3, 'c': 4}
update
나{**dict1, **dict2}
형태로 딕셔너리를 병합할 수 있다.- 파이썬 3.9 부터는
dict1 | dict2
형태의 문법도 추가된다고 한다.
7.6. 보기 좋은 딕셔너리 출력
# json 모듈 사용
>>> mapping = {'a': 23, 'b': 42, 'c': 0xc0ffee}
>>> import json
>>> json.dumps(mapping, indent=4, sort_keys=True)
'{"a": 23,\n "b": 42,\n "c": 12648430\n}'
>>> mapping['d'] = {1, 2, 3}
>>> json.dumps(mapping)
TypeError: Object of type set is not JSON serializable
# pprint 모듈 사용
>>> import pprint
>>> pprint.pprint(mapping)
{'a': 23, 'b': 42, 'c': 12648430, 'd': {1, 2, 3}}
json.dumps
나pprint.pprint
를 사용해서 딕셔너리를 보기좋게 출력할 수 있다.json
은 기본 데이터 타입이 아닌 데이터가 들어올 경우,TypyError
를 내므로 주의해야 한다.
마치며
마지막 8장은 "파이썬다운 생산성 향상 기법" 으로, 다음의 내용들을 다룬다.
- 8.1. 파이썬 모듈과 객체 탐색
- 8.2. virtualenv 로 프로젝트 의존성 격리하기
- 8.3. 바이트코드 내부 엿보기
굳이 정리할 필요 없을 거 같아 스킵하려고 한다.
참고로 나는 virtualenv 안쓰고 pyenv 쓰고 있다. virtualenv 도 써봤는데 pyenv 가 좀 더 정교한 파이썬 버전 잡기 좋은듯... 관련 링크는 여기 참고
이쯤에서 마무리 해본다. 난 꽤 재밌고 쉬우면서도 요점만 딱딱 뽑아준 책이었다고 생각한다.
책을 빌려준 쏘카와 Kyle 에게 Thanks.
'더 나은 엔지니어가 되기 위해 > 파이썬을 파이썬스럽게' 카테고리의 다른 글
Poetry 에서 바로 실행 명령 가능한 패키지 만들기 (0) | 2021.03.06 |
---|---|
Poetry 에서 로컬 패키지 add 하기 (0) | 2021.03.04 |
슬기로운 파이썬 트릭 4 - 파이썬의 일반 데이터 구조 (0) | 2020.05.30 |
슬기로운 파이썬 트릭 3 - 클래스와 객체 지향 프로그래밍 (0) | 2020.05.23 |
슬기로운 파이썬 트릭 2 - 효과적인 함수 (2) | 2020.05.22 |