#개선된 모습
def my_func(**kwargs):
for key, value in kwargs.items():
print(f'{key} = {value}')
my_func(goose='gosling', kangaroo='joey') # 3.5와 3.7이후가 다름
goose = gosling
kangaroo = joey
class MyClass:
def __init__(self):
self.alligator = 'hatchling'
self.elephant = 'calf'
a = MyClass()
for key, value in a.__dict__.items():
print(f'{key} = {value}')
alligator = hatchling
elephant = calf
파이썬은 정적 타입 지정 언어가 아니기 때문에 대부분의 경우 코드는 엄격한 클래스 계층보다는 객체의 동작이 객체의 실질적인 타입을 결정하는 덕 타이핑에 의존한다.
덕 타이핑 : 객체가 실행 시점에 어떻게 행동하는지를 기준으로 객체의 타임을 판단하는 타입 지정 방식
# 예시
# 동물 콘테스트에서 콘테스트 결과를 보여주는 프로그램을 작성
#ranks에 때하 등수 오름차순으로 등록한다고 가정하고 동작한다.
votes = {
'otter': 1281,
'polar bear': 587,
'fox': 863,
}
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 # ranks라는 딕셔너리에 name이라는 key에 맞게 생성
def get_winner(ranks):
return next(iter(ranks)) #첫번째가 무조건 1등이기 때문에 이터레이션을 한번이용하여 호출
ranks = {}
populate_ranks(votes, ranks)
print(ranks)
winner = get_winner(ranks)
print(winner)
{'otter': 1, 'fox': 2, 'polar bear': 3}
otter
# 두 번째 예시
# 프로그램의 예시가 변경되고 등수순이 아닌 알파벳 순 일때
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):
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)
# 위 코드는 key 위치의 따라 오름차순으로 정렬 그리고 딕셔너리 저장.
sorted_ranks = SortedDict()
populate_ranks(votes, sorted_ranks) #populate_rank에는 이름 내림차순 투표내림차순으로 rank가 나오게 되어있음.
print(sorted_ranks.data) #결과값이 전과 동일하게 나옴
winner = get_winner(sorted_ranks) #SortedDict에 의해 제너레이터는 keys 알파벳 순으로 되어있음.
print(winner) # 랭크순이 아닌 알파벳 순으로 나옴.
{'otter': 1, 'fox': 2, 'polar bear': 3}
fox
get_winner 구현이 populate_ranks에 맞게 딕셔너리를 이터레이션한다고 가정을 했지만 dict대신 sorteddict을 사용하여 가정성립x
문제를 해결하는 세가지 방법
#단순히 rank가 1인 key를 호출
def get_winner(ranks):
for name, rank in ranks.items():
if rank == 1:
return name
winner = get_winner(sorted_ranks)
print(winner)
otter
# isinstance 함수를 이용한 확인방법
def get_winner(ranks):
if not isinstance(ranks, dict): # (인스턴스, 클래스/데이터 타입) 맞으면 true 호출
raise TypeError('dict 인스턴스가 필요합니다')
return next(iter(ranks))
get_winner(sorted_ranks)
TypeError Traceback (most recent call last)
in
4 raise TypeError('dict 인스턴스가 필요합니다')
5 return next(iter(ranks))
----> 6 get_winner(sorted_ranks)
in get_winner(ranks)
2 def get_winner(ranks):
3 if not isinstance(ranks, dict): # (인스턴스, 클래스/데이터 타입) 맞으면 true 호출
----> 4 raise TypeError('dict 인스턴스가 필요합니다')
5 return next(iter(ranks))
6 get_winner(sorted_ranks)
TypeError: dict 인스턴스가 필요합니다
# 각 딕셔너리의 타임을 지정함으로써 지정과 다른 결과가 있을 경우 에러에서 원인을 지적한다.
from typing import Dict, MutableMapping
def populate_ranks(votes: Dict[str, int],
ranks: Dict[str, int]) -> None:
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: Dict[str, int]) -> str:
return next(iter(ranks))
class SortedDict(MutableMapping[str, int]):
def __init__(self):
self.data = {}
def __getitem__(self, key):
return self.data[key]
def __setitem__(self, key, value):
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,
}
sorted_ranks = SortedDict()
populate_ranks(votes, sorted_ranks)
print(sorted_ranks.data)
winner = get_winner(sorted_ranks)
print(winner)
{'otter': 1, 'fox': 2, 'polar bear': 3}
fox