티스토리 뷰

728x90

해당 내용과 코드는 모두 '코딩의 기술' 책을 참고한 것입니다.

 

 

counters = {
    '품퍼니켈': 2,
    '사워도우': 1,
}

key = '밀'

if key in counters:
    print(key)
    count = counters[key]
else:
    print(key) # 밀
    count = 0
  • 키가 없으면 디폴트 카운터인 값에 0을 딕셔너리에 넣고 카운터를 증가 시키는 방법으로 구현한다.
  • if문과 키를 사용함으로서 딕셔너리에서 키를 두 번 읽고, 키에 대한 값을 한 번 대입하게 되는 경우이다
try:
    count = counters[key]
except KeyError:
    count = 0

counters[key] = count + 1
print(counters) # {'품퍼니켈': 2, '사워도우': 1, '밀': 1}
  • 존재하지 않는 키에 접근할 때 발생시키는 KeyError 예외를 활용하는 방법
  • 키를 한 번만 읽고, 값을 한 번만 대입하면 되므로 더 효울적임
  • 딕셔너리에는 이런 식으로 키가 존재하면 그 값을 가져오고, 존재하지 않으면 디폴트 값을 반환하는 흐름이 자주 일어난다.
count = counters.get(key, 0)
counters[key] = count + 1
print(counters) # {'품퍼니켈': 2, '사워도우': 1, '밀': 1}
  • 그러면 dict 내장 타입에는 이런 작업을 수행하는 get 의 메서드가 있음
  • get의 두 번째 인자는 첫 번째 인자인 키가 딕셔너리에 들어 있지 않을 때 돌려줄 디폴트 값임
  • 키를 한 번만 읽고 키를 한 번만 대입하는 방법
if key not in counters:
    counters[key] = 0
counters[key] += 1

if key in counters:
    counters[key] += 1
else:
    counters[key] = 1

try:
    counters[key] += 1
except KeyError:
    counters[key] = 1
  • in 식과 KeyError 를 사용하는 방식을 여러 방법으로 더 짧게 쓸 수도 있음
  • 하지만 어느 방식을 써도 대입이 중복되므로 코드 가독성이 떨어짐
votes = {
    '바게트' : ['철수', '순이'],
    '치아바타': ['하니', '유리']    
}
key = '브리오슈'
who = '단이'

if key in votes:
    names = votes[key]
else:
    votes[key] = names = []
    print(votes) # {'바게트': ['철수', '순이'], '치아바타': ['하니', '유리'], '브리오슈': []}

names.append(who)
print(votes) # {'바게트': ['철수', '순이'], '치아바타': ['하니', '유리'], '브리오슈': ['단이']}
  • in 을 사용하면 키가 있는 경우에는 키를 두 번 읽어야 하고, 키가 없는 경우에는 값을 한 번 대입하게 됨
  • 이 예제는 키가 존재하지 않을 때 빈 리스트를 통해 디폴트 값으로 대입할 수 있음
  • 이중 대입문인 votes[key] names = [] 는 키 대입을 두 줄이 아닌 한 줄로 처리
  • 디폴트 값으로 빈 리스트를 딕셔너리에 넣고 나면 참조를 통해 내용 변경이 어려우므로 append를 호출한 다음 리스트를 다시 딕셔너리에 대입할 필요가 없다
try:
    names = votes[key]
except KeyError:
    votes[key] = names = []
    
names.append(who)
print(votes) # {'바게트': ['철수', '순이'], '치아바타': ['하니', '유리'], '브리오슈': ['단이']}

if (names := votes.get(key)) is None:
    votes[key] = names = []
    
names.append(who)
print(votes) # {'바게트': ['철수', '순이'], '치아바타': ['하니', '유리'], '브리오슈': ['단이']}
  • 좋은 코드
naems = votes.setdefault(key, [])
names.append(who)
print(votes) # {'바게트': ['철수', '순이'], '치아바타': ['하니', '유리'], '브리오슈': ['단이']}
  • setdefault 메서드가 있다
  • 이는 딕셔너리에서 키를 사용해 값을 가져오려고 시도함
  • 해당 메서드는 키가 없으면 제공받은 디폴트 값을 키에 연관시켜 딕셔너리에 대입한 다음, 키에 연관된 값을 반환함
  • 한 가지 함정은 키가 없으면 setdefault 에 전달된 디폴트 값이 별도로 복사되지 않고 딕셔너리에 직접 대입됨
data = {}
key = 'foo'
value = []
data.setdefault(key, value)
print('이전', data)
value.append('hello')
print('이후', data)
# 이전 {'foo': []}
# 이후 {'foo': ['hello']}
  • 키에 해당하는 디폴트 값을 setdefault 에 전달할 때마다 그 값을 새로 만들어야 함
  • 즉, 호출할 때마다 리스트를 만들어야 해서 성능이 크게 저하됨
count = counters.setdefault(key, 0)
counters[key] = count + 1
print(counters) # {'품퍼니켈': 2, '사워도우': 1, '밀': 5, 'foo': 1}
  • 여기서는 굳이 setdefault 를 사용할 이유가 없다
  • 카운터를 증가시키면 default 값이 굳이 필요 없기 때문이다
728x90
댓글