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) # ... # 위 방법은 타입의 차이를 감지하여 적절한 타입이 아니면 오류를 발생시킨다. # 이 방법은 정적 타입 안전성과 런타임 성능을 가장 잘 조합한다. 참고자료: