votes = [
'otter': 1281,
'polar bear': 587,
'fox': 863,
'my': 1,
]
def populate_ranks(votes, ranks):
names = list(votes.keys())
names.sort(key=votes.get, reverse=True)
for i, name in enumerate(names, 1):
ranks[name] = i
def get_winner(ranks):
return next(iter(ranks))
ranks = {}
populate_ranks(votes, ranks)
print(ranks)
winner = het_winner(ranks)
print(winner)
from collections.abc import MutableMapping
class SortedDict(MutableMapping):
def __init__(self):
self.data = {}
def __getitem__(self, key):
return self.data[key]
def __setitem__(self, key, value):
return self.data[key] = value
def __delitem__(self, key):
del self.data[key]
def __iter__(self):
keys = list(self.data.keys())
keys.sort()
for key in keys:
yield key
def __len__(self):
return len(self.data)
votes = [
'otter': 1281,
'polar bear': 587,
'fox': 863,
'my': 1,
]
def populate_ranks(votes, ranks):
names = list(votes.keys())
names.sort(key=votes.get, reverse=True)
for i, name in enumerate(names, 1):
ranks[name] = i
def get_winner(ranks):
return next(iter(ranks))
sorted_ranks = SortedDict()
populate_ranks(votes, sorted_ranks)
print(sorted_ranks)
winner = get_winner(sorted_ranks)
print(winner)
# 표준 딕셔너리의 프로토콜을 지켰다고해서 get_winner 메소드가 딕셔너리의
# 삽입 순서에 맞게 딕셔너리를 이터레이션한다고 가정하면 안된다
위 문제를 해결할 방법은 3가지가 있다.
1. get_winner 함수를 딕셔너리의 순서에 관계없이 구현
def get_winner(ranks):
for name, rank in ranks.items():
if rank == 1:
return name
2. 타입 검사
def get_winner(ranks):
if not isinstance(ranks, dict):
raise TypeError('need dict instance'
return next(iter(ranks))
3. 타입 애너테이션(Type Annotation)
from typing import Dict, MutableMapping
def populate_ranks(ranks: Dict[str, int],
votes: Dict[str, int]) -> None:
names = list(votes.keys())
votes.sort(key=votes.get, reverse=True)
for rank, name in enumerate(names, 1):
ranks[name] = rank
def get_winner(ranks: Dict[str, int]) -> None:
return next(iter(ranks)
# ...
# 위 방법은 타입의 차이를 감지하여 적절한 타입이 아니면 오류를 발생시킨다.
# 이 방법은 정적 타입 안전성과 런타임 성능을 가장 잘 조합한다.