전문가를 위한 파이썬을 정리한 내용입니다.
dict
해시 가능하다?
- 수명 주기 동안 결코 변하지 않는 해시 값을 가지고 있고(hash()메서드가 필요하다) 다른 객체와 비교할 수 있으면(
__eq__()
메서드가 필요하다). 객체를 해시 가능하다고 합니다.
- 원자적 불변형(str, byte, 수치형)은 모수 해시 가능합니다. frozenset도 언제나 해시 가능합니다.
- 리스트는 해시 가능하지 않습니다. (가변이기 때문)
지능형 딕셔너리
- 모든 반복형 객체에서 키-값 쌍을 생성함으로써 딕셔너리 객체를 만들 수 있습니다.
DIAL_CODES = [
(86, 'China'),
(91, 'India'),
(02, 'Korea')
]
country_code = {country: code for code, country in DIAL_CODES}
존재하지 않는 키를 setdefault()로 처리
- 조기 실패(fail-fast)철학에 따라, 존재하지 않는 키 k로 d[k]를 접근하면 dict는 오류를 발생시킵니다.
- KeyError를 처리하는 것보다 기본값을 사용하는 것이 더 편리한 경우에는 d[k] 대신 d.get(k, default)를 사용하는 것이 좋습니다.
- 그러나 발견한 값을 갱신할 때, 해당 객체가 가변 객체면
__getitem__()
이나 get()
메서드는 보기 어색하며, 효율성도 떨어집니다.
- 그 이유는
get()
을 쓰는 경우네는 키를 두 번 검색하고(단어가 없을 때는 세 번 검색), setdefault()는 단 한 번만 검색해서 키가 없을 때를 잘 처리할 수 있습니다.
융통성 있게 키를 조회하는 매핑
- 검색할 때 키가 존재하지 않으면 어떤 특별한 값을 반환하는 매핑이 있으면 편리한 때가 종종 있습니다.
이 때 두 가지 방법이 존재합니다.
- 하나는 평범한 dict 대신 defaultdict를 사용하는 바업
- 다른 하나는 dict 등의 매핑형을 상속해서
__missing__()
메서드를 추가하는 방법입니다.
defaultdict : 존재하지 않는 키에 대한 또 다른 처리
- 작동하는 방식은, defaultdcit 객체를 생성할 때 존재하지 않는 키 인수로
__getitem__)_
메서드를 호출할 때마다 기본값을 생성하기 위해 사용되는 콜러블(전달받은 object 인자가 호출 가능한지 여부를 판단)을 제공하는 것입니다.
- 예를 들어, dd = defaultdict(list) 코드로 기본 defaultdict 객체를 생성한 후, dd에 존재하지 않는 키인 'new-key'로 dd['new-key'] 표현식을 실행하면 다음과 같이 처리 됩니다.
- 리스트를 새로 생성하기 위해 list()를 호출합니다.
- 'new-key'를 키로 사용해서 새로운 리스트를 dd에 삽입합니다.
- 리스트에 대한 참조를 반환합니다.
- 기본값을 생성하는 콜러블은 default_factory라는 객체 속성에 저장됩니다.
default의 __getitem__()
호출에 대한 기본값을 제공하기 위해 호출되며, 다른 메서드를 통해서는 호출되지 않습니다. 예를 들어 dd가 defaultdict 형이며, k가 존재하지 않는 키면, dd[k]는 default_factory를 호출해서 기본값을 생성하지만, dd.get(k)는 단지 None을 반환할 뿐입니다.
- 실제 defaultdict가 default_factory를 호출하게 만드는 매커니즘은
__missing__()
특수 메서드에 의존합니다.
missing 특수 메서드
- 존재하지 않는 키를 처리하는 메서드
- dict에는 정의되어 있지 않지만 dict는 이 메서드를 알고 있습니다.
따라서 dict 클래스를 상속하고 __missing__()
메서드를 정의하면, dict.__getitem__()
표준 메서드가 키를 발견할 수 없을 때 KeyError를 발생시키지 않고 __missing__()
메서드를 호출합니다.
__missing__()
메서드는 d[k] 연산자를 사용하는 경우 등 __getitem__()
메서드를 사용할 때만 호출됩니다.
in 연산자를 구현하는 get()이나 __contains__()
메서드 등 키를 검색하는 다른 메서드에는 __missing__()
메서드가 영향을 미치지 않습니다.
파이썬 3에서는 아주 큰 매핑의 경우에도 k in my_dict.keys()
형태의 검색이 효율적입니다. dict.keys()는 집합과 비슷한 뷰를 반환하는데, 집합에 포함되었는지 여부를 검사하는 것은 딕셔너리만큼 빠르기 때문입니다.
k in my_list
연산이 리스트를 검색해야 하므로 딕셔너리가 커지면 효율이 떨어집니다.
여러 가지 매핑형
collections.OrderedDict
- 키를 삽입한 순서대로 유지함으로써 항목을 반복하는 순서를 예측할 수 있습니다. OrderedDict의 popitem() 메서드는 기본적으로 최근에 삽입한 항목을 꺼내지만, my_odict.popitem(last=True) 형태로 호출하면 처음 삽입한 항목을 꺼냅니다.
collections.ChainMap
- 매핑들의 목록을 담고 있으며 한꺼번에 모두 검색할 수 있습니다.
- 각 매핑을 차례대로 검색하고, 그중 하나에서라도 키가 검색되면 성공합니다.
import builtins
pylookup = ChainMap(locals(), globals(), vars(builtins))
collections.Counter
- 모든 키에 정수형 카운터를 갖고 있는 매핑, 기존 키를 갱신하면 카운터가 늘어납니다.
- 카운터는 해시 가능한 객체(키)나 한 항목이 여러 번 들어갈 수 있는 다중 집합에서 객체의 수를 세기 위해 사용할 수 있습니다.
- Counter 클래스는 합계를 구하기 위한 +와 - 연산자를 구현하며, n개의 가장 널리 사용된 항목과 그들의 구성된 튜플의 리스트를 반환하는 most_common([n]) 등의 메서드를 제공합니다.
>>> ct = collection.Counter('abracadabra')
>>> ct
Counter ({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
>>> ct.update('aaaaazzz')
>>> ct
Counter({'a': 10, 'z': 3, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
>>> ct.most_common(2)
[('a', 10), ('z', 3)]