Python 표준 라 이브 러 리 의 collections 패키지 사용 튜 토리 얼

머리말
Python 은 우리 에 게 4 가지 기본 적 인 데이터 구 조 를 제공 했다.list,tuple,dict,set.그러나 데이터 양 이 비교적 많은 상황 을 처리 할 때 이 4 가지 데이터 구 조 는 현저히 단일 하 다.예 를 들 어 list 는 배열 로 서 특정한 상황 에 삽입 하 는 효율 이 비교적 낮 고 가끔 은 우리 도 질서 있 는 dict 를 유지 해 야 한다.그래서 이 럴 때 우 리 는 Python 표준 라 이브 러 리 를 사용 하여 우리 에 게 제공 하 는 collection s 가방 을 사용 해 야 합 니 다.이것 은 여러 개의 유용 한 집합 류 를 제공 합 니 다.이런 집합 류 를 능숙 하 게 파악 하면 우리 가 쓴 코드 를 더욱 Python 으로 만 들 수 있 을 뿐만 아니 라 우리 프로그램의 운행 효율 도 높 일 수 있 습 니 다.
defaultdictdefaultdict(default_factory)일반적인 dict 에 default 를 추가 하 였 습 니 다.factory,key 가 존재 하지 않 을 때 해당 유형의 value,default 를 자동 으로 생 성 합 니 다.factory 매개 변 수 는 list,set,int 등 각종 합 법 적 인 유형 으로 지정 할 수 있 습 니 다.
우 리 는 현재 다음 과 같은 list 가 있 습 니 다.비록 우 리 는 5 개의 데 이 터 를 가지 고 있 지만 자세히 관찰 한 결과 우 리 는 3 가지 color 만 있 지만 모든 color 는 여러 개의 값 에 대응 합 니 다.현재 이 list 를 dict 로 변환 하려 고 합 니 다.이 dict 의 key 는 하나의 color 에 대응 하고 dict 의 value 는 하나의 list 로 color 에 대응 하 는 여러 값 을 저장 합 니 다.우 리 는 이 문 제 를 해결 하기 위해defaultdict(list)를 사용 할 수 있다.

>>> from collections import defaultdict
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
...  d[k].append(v)
...
>>> sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
이상 등가:

>>> d = {}
>>> for k, v in s:
...  d.setdefault(k, []).append(v)
...
>>> sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
만약 우리 가 중복 되 는 요 소 를 포함 하고 싶 지 않다 면 사용 을 고려 할 수 있다defaultdict(set).set 가 list 에 비해 다른 점 은 set 에 같은 요소 가 존재 하지 않 는 다 는 것 입 니 다.

>>> from collections import defaultdict
>>> s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
>>> d = defaultdict(set)
>>> for k, v in s:
...  d[k].add(v)
...
>>> sorted(d.items())
[('blue', {2, 4}), ('red', {1, 3})]
OrderedDict
Python 3.6 이전의 dict 는 무질서 하 였 으 나,어떤 경우 에는 dict 의 질서 성 을 유지 해 야 합 니 다.이 럴 때 OrderedDict 를 사용 할 수 있 습 니 다.이것 은 dict 의 subclass 이지 만,dict 를 바탕 으로 dict 의 질서 형 을 유지 하 였 습 니 다.다음은 사용 방법 을 살 펴 보 겠 습 니 다.

>>> # regular unsorted dictionary
>>> d = {'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2}
>>> # dictionary sorted by key
>>> OrderedDict(sorted(d.items(), key=lambda t: t[0]))
OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])
>>> # dictionary sorted by value
>>> OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])
>>> # dictionary sorted by length of the key string
>>> OrderedDict(sorted(d.items(), key=lambda t: len(t[0])))
OrderedDict([('pear', 1), ('apple', 4), ('orange', 2), ('banana', 3)])
popitem(last=True)방법 을 사용 하면 LIFO(선진 후 출)순서에 따라 dict 의 key-value 를 삭제 할 수 있 습 니 다.즉,마지막 으로 삽 입 된 키 쌍 을 삭제 합 니 다.last=False 는 FIFO(선진 선 출)에 따라 dict 의 key-value 를 삭제 합 니 다.

>>> d = {'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2}
>>> # dictionary sorted by key
>>> d = OrderedDict(sorted(d.items(), key=lambda t: t[0]))
>>> d
OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])
>>> d.popitem()
('pear', 1)
>>> d.popitem(last=False)
('apple', 4)
move_to_end(key, last=True)를 사용 하여 질서 있 는 OrderedDict 대상 의 key-value 순 서 를 바 꿉 니 다.이 방법 을 통 해 정렬 된 OrderedDict 대상 중의 임의의 key-value 를 사전 의 시작 이나 끝 에 삽입 할 수 있 습 니 다.

>>> d = OrderedDict.fromkeys('abcde')
>>> d
OrderedDict([('a', None), ('b', None), ('c', None), ('d', None), ('e', None)])
>>> d.move_to_end('b')
>>> d
OrderedDict([('a', None), ('c', None), ('d', None), ('e', None), ('b', None)])
>>> ''.join(d.keys())
'acdeb'
>>> d.move_to_end('b', last=False)
>>> ''.join(d.keys())
'bacde'
deque
list 에 데 이 터 를 저장 하 는 장점 은 색인 에 따라 요 소 를 찾 는 것 이 빠 르 지만 요 소 를 삽입 하고 삭제 하 는 것 이 느 립 니 다.list 는 배열 을 바탕 으로 이 루어 지기 때 문 입 니 다.deque 는 삽입 과 삭 제 를 위 한 양 방향 목록 으로 대기 열 과 스 택 에 적합 하 며 스 레 드 가 안전 합 니 다.
list 는 append 와 pop 방법 만 제공 하여 list 의 끝 부분 에서 요 소 를 삽입/삭제 합 니 다.deque 는 appendleft/opleft 등 방법 을 추가 하여 요소 의 시작 부분 에 요 소 를 삽입/삭제 할 수 있 도록 합 니 다.또한 deque 를 사용 하여 대기 열 양쪽 에 있 는 append 나 pop 요 소 를 사용 하 는 알고리즘 의 복잡 도 는 대략 O(1)이지 만 list 대상 이 목록 의 길이 와 데이터 위 치 를 바 꾸 는 작업,예 를 들 어pop(0)insert(0, v)작업 의 복잡 도 는 O(n)에 달한다.

>>> from collections import deque
>>> dq = deque(range(10), maxlen=10)
>>> dq
deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
>>> dq.rotate(3)
>>> dq
deque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6], maxlen=10)
>>> dq.rotate(-4)
>>> dq
deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0], maxlen=10)
>>> dq.appendleft(-1)
>>> dq
deque([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
>>> dq.extend([11, 22, 33])
>>> dq
deque([3, 4, 5, 6, 7, 8, 9, 11, 22, 33], maxlen=10)
>>> dq.extendleft([10, 20, 30, 40])
>>> dq
deque([40, 30, 20, 10, 3, 4, 5, 6, 7, 8], maxlen=10)
Counter
Count 는 관련 요소 의 출현 횟수 를 통계 하 는 데 쓰 인 다.

>>> from collections import Counter
>>> ct = Counter('abracadabra')
>>> ct
Counter({'a': 5, 'r': 2, 'b': 2, 'd': 1, 'c': 1})
>>> ct.update('aaaaazzz')
>>> ct
Counter({'a': 10, 'z': 3, 'r': 2, 'b': 2, 'd': 1, 'c': 1})
>>> ct.most_common(2)
[('a', 10), ('z', 3)]
>>> ct.elements()
<itertools.chain object at 0x7fbaad4b44e0>
namedtuplenamedtuple(typename, field_names)tuple 의 요 소 를 사용 하여 프로그램 을 더욱 읽 을 수 있 도록 합 니 다.

>>> from collections import namedtuple
>>> City = namedtuple('City', 'name country population coordinates')
>>> tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
>>> tokyo
City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722, 139.691667))
>>> tokyo.population
36.933
>>> tokyo.coordinates
(35.689722, 139.691667)
>>> tokyo[1]
'JP'

>>> City._fields
('name', 'country', 'population', 'coordinates')
>>> LatLong = namedtuple('LatLong', 'lat long')
>>> delhi_data = ('Delhi NCR', 'IN', 21.935, LatLong(28.613889, 77.208889))
>>> delhi = City._make(delhi_data)
>>> delhi._asdict()
OrderedDict([('name', 'Delhi NCR'), ('country', 'IN'), ('population', 21.935),
   ('coordinates', LatLong(lat=28.613889, long=77.208889))])
>>> for key, value in delhi._asdict().items():
  print(key + ':', value)
name: Delhi NCR
country: IN
population: 21.935
coordinates: LatLong(lat=28.613889, long=77.208889)
ChainMap
ChainMap 은 여러 사전 을 통합 하 는 데 사용 할 수 있 습 니 다.

>>> from collections import ChainMap
>>> d = ChainMap({'zebra': 'black'}, {'elephant': 'blue'}, {'lion': 'yellow'})
>>> d['lion'] = 'orange'
>>> d['snake'] = 'red'
>>> d
ChainMap({'lion': 'orange', 'zebra': 'black', 'snake': 'red'},
   {'elephant': 'blue'}, {'lion': 'yellow'})

>>> del d['lion']
>>> del d['elephant']
Traceback (most recent call last):
 File "/usr/lib/python3.5/collections/__init__.py", line 929, in __delitem__
 del self.maps[0][key]
KeyError: 'elephant'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "/usr/lib/python3.5/collections/__init__.py", line 931, in __delitem__
 raise KeyError('Key not found in the first mapping: {!r}'.format(key))
KeyError: "Key not found in the first mapping: 'elephant'"
del['elephant']의 오류 정 보 를 통 해 알 수 있 듯 이 키 값 을 바 꾸 는 조작 ChainMap 은 첫 번 째 사전self.maps[0][key]에서 만 찾 을 수 있 습 니 다.새로 추 가 된 키 값 쌍 도 첫 번 째 사전 에 추 가 됩 니 다.ChainMap 을 개선 하여 이 문 제 를 해결 합 니 다.

class DeepChainMap(ChainMap):
 'Variant of ChainMap that allows direct updates to inner scopes'
 def __setitem__(self, key, value):
  for mapping in self.maps:
   if key in mapping:
    mapping[key] = value
    return
  self.maps[0][key] = value
 def __delitem__(self, key):
  for mapping in self.maps:
   if key in mapping:
    del mapping[key]
    return
  raise KeyError(key)
>>> d = DeepChainMap({'zebra': 'black'}, {'elephant': 'blue'}, {'lion': 'yellow'})
>>> d['lion'] = 'orange'   # update an existing key two levels down
>>> d['snake'] = 'red'   # new keys get added to the topmost dict
>>> del d['elephant']   # remove an existing key one level down
DeepChainMap({'zebra': 'black', 'snake': 'red'}, {}, {'lion': 'orange'})
new 사용 가능child 래 deepcopy 체인 맵:

>>> from collections import ChainMap
>>> a = {'a': 'A', 'c': 'C'}
>>> b = {'b': 'B', 'c': 'D'}
>>> m = ChainMap({'a': 'A', 'c': 'C'}, {'b': 'B', 'c': 'D'})
>>> m
ChainMap({'a': 'A', 'c': 'C'}, {'b': 'B', 'c': 'D'})
>>> m['c']
'C'
>>> m.maps
[{'c': 'C', 'a': 'A'}, {'c': 'D', 'b': 'B'}]
>>> a['c'] = 'E'
>>> m['c']
'E'
>>> m
ChainMap({'c': 'E', 'a': 'A'}, {'c': 'D', 'b': 'B'})

>>> m2 = m.new_child()
>>> m2['c'] = 'f'
>>> m2
ChainMap({'c': 'f'}, {'c': 'E', 'a': 'A'}, {'c': 'D', 'b': 'B'})
>>> m
ChainMap({'c': 'E', 'a': 'A'}, {'c': 'D', 'b': 'B'})
>>> m2.parents
ChainMap({'c': 'E', 'a': 'A'}, {'c': 'D', 'b': 'B'})
UserDict
사전 을 개선 하고 사전 을 조회 할 때 key 를 str 형식 으로 변환 합 니 다.

class StrKeyDict0(dict):
 def __missing__(self, key):
  if isinstance(key, str):
   raise KeyError(key)
  return self[str(key)]
 def get(self, key, default=None):
  try:
   return self[key]
  except KeyError:
   return default
 def __contains__(self, key):
  return key in self.keys() or str(key) in self.keys()
위의 프로그램 을 설명 하 십시오.
  • 재missing__중 isinstance(key,str)는 필수 입 니 다.왜 그런 지 생각해 보 세 요.key 가 존재 하지 않 는 다 고 가정 하면 infinite recursion 을 초래 할 수 있 기 때문에 self[str(key)]는 다시 를 호출 합 니 다.getitem__。
  • __contains__또한 반드시 이 루어 져 야 합 니 다.k in d 일 때 호출 되 기 때 문 입 니 다.그러나 검색 에 실패 하 더 라 도 를 호출 하지 않 습 니 다.missing__。 에 대하 여contains__또 하나의 세부 사항 은 우리 가 사용 하지 않 았 다 는 것 이다k in my_dict.왜냐하면str(key) in self의 형식 은 재 귀 호출contains__。
  • 여기 서 강조 하 자 면 Python 2.x 에서 dict.keys()는 list 를 되 돌려 줍 니 다.이것 은 k in my 를 의미 합 니 다.list 는 list 를 옮 겨 다 녀 야 합 니 다.Python 3.x 에서 dict.keys()를 최적화 시 켰 습 니 다.성능 이 더욱 높 습 니 다.view 는 set 처럼 상세 한 참고공식 문서를 되 돌려 줍 니 다.
    위의 이 예 는 UserDict 로 고 칠 수 있 고 모든 key 를 str 형식 으로 저장 할 수 있 으 며 이런 쓰기 방법 은 더욱 간결 하 다.
    
    import collections
    class StrKeyDict(collections.UserDict):
     def __missing__(self, key):
      if isinstance(key, str):
       raise KeyError(key)
      return self[str(key)]
     def __contains__(self, key):
      return str(key) in self.data
     def __setitem__(self, key, item):
      self.data[str(key)] = item
    UserDict 는 Mutable Mapping 과 Mapping 의 하위 클래스 로 Mutable Mapping.update 와 Mapping.get 두 가지 중요 한 방법 을 계승 하 였 기 때문에 위 에서 get 방법 을 다시 쓰 지 않 았 습 니 다.소스 코드에서 그의 실현 과 우리 위의 실현 은 차이 가 많 지 않 습 니 다.
    총결산
    이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

    좋은 웹페이지 즐겨찾기