"collections" --- 컨테이너 데이터형
***********************************

**소스 코드:** Lib/collections/__init__.py

======================================================================

이 모듈은 파이썬의 범용 내장 컨테이너 "dict", "list", "set" 및 "tuple"
에 대한 대안을 제공하는 특수 컨테이너 데이터형을 구현합니다.

+-----------------------+----------------------------------------------------------------------+
| "namedtuple()"        | 이름 붙은 필드를 갖는 튜플 서브 클래스를 만들기 위한 팩토리 함수     |
+-----------------------+----------------------------------------------------------------------+
| "deque"               | 양쪽 끝에서 빠르게 추가와 삭제를 할 수 있는 리스트류 컨테이너        |
+-----------------------+----------------------------------------------------------------------+
| "ChainMap"            | 여러 매핑의 단일 뷰를 만드는 딕셔너리류 클래스                       |
+-----------------------+----------------------------------------------------------------------+
| "Counter"             | *해시 가능* 객체를 세는 데 사용하는 딕셔너리 서브 클래스             |
+-----------------------+----------------------------------------------------------------------+
| "OrderedDict"         | 항목이 추가된 순서를 기억하는 딕셔너리 서브 클래스                   |
+-----------------------+----------------------------------------------------------------------+
| "defaultdict"         | 누락된 값을 제공하기 위해 팩토리 함수를 호출하는 딕셔너리 서브 클래  |
|                       | 스                                                                   |
+-----------------------+----------------------------------------------------------------------+
| "UserDict"            | 더 쉬운 딕셔너리 서브 클래싱을 위해 딕셔너리 객체를 감싸는 래퍼      |
+-----------------------+----------------------------------------------------------------------+
| "UserList"            | 더 쉬운 리스트 서브 클래싱을 위해 리스트 객체를 감싸는 래퍼          |
+-----------------------+----------------------------------------------------------------------+
| "UserString"          | 더 쉬운 문자열 서브 클래싱을 위해 문자열 객체를 감싸는 래퍼          |
+-----------------------+----------------------------------------------------------------------+


"ChainMap" 객체
===============

Added in version 3.3.

"ChainMap" 클래스는 여러 매핑을 빠르게 연결하여 단일 단위로 취급 할 수
있도록 합니다. 종종 새로운 딕셔너리를 만들고 여러 "update()" 호출을 실
행하는 것보다 훨씬 빠릅니다.

이 클래스는 중첩된 스코프를 시뮬레이션하는 데 사용할 수 있으며 템플릿
에 유용합니다.

class collections.ChainMap(*maps)

   "ChainMap"은 여러 딕셔너리나 다른 매핑을 함께 묶어 갱신 가능한 단일
   뷰를 만듭니다. *maps*가 지정되지 않으면, 새 체인에 항상 하나 이상의
   매핑이 있도록, 빈 딕셔너리 하나가 제공됩니다.

   하부 매핑은 리스트에 저장됩니다. 이 리스트는 공개이며 *maps* 어트리
   뷰트를 사용하여 액세스하거나 갱신할 수 있습니다. 다른 상태는 없습니
   다.

   조회는 키를 찾을 때까지 하부 매핑을 검색합니다. 반면에, 쓰기, 갱신
   및 삭제는 첫 번째 매핑에만 작동합니다.

   "ChainMap"은 하부 매핑을 참조로 통합합니다. 따라서 하부 매핑 중 하
   나가 갱신되면 해당 변경 사항이 "ChainMap"에 반영됩니다.

   일반적인 딕셔너리 메서드가 모두 지원됩니다. 또한, *maps* 어트리뷰트
   , 새 서브 컨텍스트를 만드는 메서드 및 첫 번째 매핑을 제외한 모든 것
   에 액세스하는 프로퍼티가 있습니다:

   maps

      사용자 갱신 가능한 매핑 리스트. 리스트는 먼저 검색되는 것에서 나
      중에 검색되는 순서를 따릅니다. 저장된 유일한 상태이며 검색할 매
      핑을 변경하도록 수정할 수 있습니다. 리스트는 항상 하나 이상의 매
      핑이 포함되어야 합니다.

   new_child(m=None, **kwargs)

      새 맵과 그 뒤로 현재 인스턴스의 모든 맵을 포함하는 새 "ChainMap"
      을 반환합니다. "m"이 지정되면, 매핑 리스트의 맨 앞에 놓이는 새
      맵이 됩니다. 지정하지 않으면, 빈 딕셔너리가 사용되므로
      "d.new_child()" 호출은 "ChainMap({}, *d.maps)"과 동등합니다. 키
      워드 인자가 지정되면, 전달된 맵이나 새로운 빈 딕셔너리를 갱신합
      니다. 이 메서드는 어떤 부모 매핑에 있는 값도 변경하지 않으면서
      갱신할 수 있는 서브 컨텍스트를 만드는 데 사용됩니다.

      버전 3.4에서 변경: 선택적 "m" 매개 변수가 추가되었습니다.

      버전 3.10에서 변경: Keyword arguments support was added.

   parents

      첫 번째 맵을 제외하고 현재 인스턴스의 모든 맵을 포함하는 새
      "ChainMap"을 반환하는 프로퍼티. 검색에서 첫 번째 맵을 건너뛰려고
      할 때 유용합니다. 사용 사례는 *중첩된 스코프*에서 사용되는
      "nonlocal" 키워드와 유사합니다. 사용 사례는 내장 "super()" 함수
      와도 유사합니다. "d.parents"에 대한 참조는
      "ChainMap(*d.maps[1:])"과 동등합니다.

   "ChainMap"의 이터레이션 순서는 매핑을 마지막에서 첫 번째 방향으로
   스캔하여 결정됩니다:

      >>> baseline = {'music': 'bach', 'art': 'rembrandt'}
      >>> adjustments = {'art': 'van gogh', 'opera': 'carmen'}
      >>> list(ChainMap(adjustments, baseline))
      ['music', 'art', 'opera']

   이것은 마지막 매핑에서 시작하는 일련의 "dict.update()" 호출과 같은
   순서를 제공합니다:

      >>> combined = baseline.copy()
      >>> combined.update(adjustments)
      >>> list(combined)
      ['music', 'art', 'opera']

   버전 3.9에서 변경: **PEP 584**에 지정된, "|"와 "|=" 연산자에 대한
   지원이 추가되었습니다.

더 보기:

  * Enthought CodeTools 패키지의 MultiContext 클래스에는 체인의 모든
    매핑으로의 쓰기를 지원하는 옵션이 있습니다.

  * 템플릿을 위한 Django의 Context 클래스는 읽기 전용 매핑 체인입니다.
    또한 "new_child()" 메서드와 "parents" 프로퍼티와 유사하게 컨텍스트
    를 푸시(push)하고 팝(pop) 하는 기능이 있습니다.

  * 중첩된 컨텍스트 조리법에는 쓰기와 기타 변경이 첫 번째 매핑에만 적
    용되는지 아니면 체인의 모든 매핑에 적용되는지를 제어하는 옵션이 있
    습니다.

  * 매우 단순화된 체인 맵의 읽기 전용 버전


"ChainMap" 예제와 조리법
------------------------

이 절에서는 체인 맵으로 작업하는 다양한 접근 방식을 보여줍니다.

파이썬의 내부 조회 체인을 시뮬레이션하는 예:

   import builtins
   pylookup = ChainMap(locals(), globals(), vars(builtins))

사용자 지정 명령 줄 인자가 환경 변수보다 우선하고, 환경 변수는 기본값
보다 우선하도록 하는 예:

   import os, argparse

   defaults = {'color': 'red', 'user': 'guest'}

   parser = argparse.ArgumentParser()
   parser.add_argument('-u', '--user')
   parser.add_argument('-c', '--color')
   namespace = parser.parse_args()
   command_line_args = {k: v for k, v in vars(namespace).items() if v is not None}

   combined = ChainMap(command_line_args, os.environ, defaults)
   print(combined['color'])
   print(combined['user'])

중첩된 컨텍스트를 시뮬레이션하기 위해 "ChainMap" 클래스를 사용하는 예
제 패턴:

   c = ChainMap()        # 루트 컨텍스트를 만듭니다
   d = c.new_child()     # 중첩된 자식 컨텍스트를 만듭니다
   e = c.new_child()     # c의 자식, d와 독립적입니다
   e.maps[0]             # 현재 컨텍스트 딕셔너리 -- 파이썬의 locals()와 유사합니다
   e.maps[-1]            # 루트 컨텍스트 -- 파이썬의 globals()와 유사합니다
   e.parents             # 둘러싼 컨텍스트 체인 -- 파이썬의 nonlocal과 유사합니다

   d['x'] = 1            # 현재 컨텍스트에 값을 설정합니다
   d['x']                # 컨텍스트 체인에서 첫 번째 키를 가져옵니다
   del d['x']            # 현재 컨텍스트에서 지웁니다
   list(d)               # 모든 중첩된 값
   k in d                # 모든 중첩된 값을 검사합니다
   len(d)                # 중첩된 값의 개수
   d.items()             # 모든 중첩된 항목
   dict(d)               # 일반 딕셔너리로 펼칩니다

"ChainMap" 클래스는 체인의 첫 번째 매핑만 갱신(쓰기와 삭제)하지만, 조
회는 전체 체인을 검색합니다. 그러나, 깊은 쓰기와 삭제가 필요하면, 체인
의 더 깊은 곳에서 발견된 키를 갱신하는 서브 클래스를 쉽게 만들 수 있습
니다:

   class DeepChainMap(ChainMap):
       '내부 스코프를 직접 갱신할 수 있는 ChainMap의 변형'

       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'         # 두 수준 아래에 있는 기존 키를 갱신합니다
   >>> d['snake'] = 'red'           # 새 키를 최상단 딕셔너리에 추가합니다
   >>> del d['elephant']            # 한 수준 아래에 있는 기존 키를 삭제합니다
   >>> d                            # 결과를 표시합니다
   DeepChainMap({'zebra': 'black', 'snake': 'red'}, {}, {'lion': 'orange'})


"Counter" 객체
==============

편리하고 빠르게 개수를 세도록 지원하는 계수기 도구가 제공됩니다. 예를
들면:

   >>> # 목록에 있는 단어의 빈도를 집계합니다
   >>> cnt = Counter()
   >>> for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
   ...     cnt[word] += 1
   ...
   >>> cnt
   Counter({'blue': 3, 'red': 2, 'green': 1})

   >>> # 햄릿에서 가장 흔한 단어를 찾습니다
   >>> import re
   >>> words = re.findall(r'\w+', open('hamlet.txt').read().lower())
   >>> Counter(words).most_common(10)
   [('the', 1143), ('and', 966), ('to', 762), ('of', 669), ('i', 631),
    ('you', 554),  ('a', 546), ('my', 514), ('hamlet', 471), ('in', 451)]

class collections.Counter(**kwargs)
class collections.Counter(iterable, /, **kwargs)
class collections.Counter(mapping, /, **kwargs)

   "Counter"는 *해시 가능* 객체를 세기 위한 "dict" 서브 클래스입니다.
   요소가 딕셔너리 키로 저장되고 개수가 딕셔너리값으로 저장되는 컬렉션
   입니다. 개수는 0이나 음수를 포함하는 임의의 정숫값이 될 수 있습니다
   . "Counter" 클래스는 다른 언어의 백(bag)이나 멀티 셋(multiset)과 유
   사합니다.

   요소는 *이터러블*로부터 계산되거나 다른 *매핑*(또는 계수기)에서 초
   기화됩니다:

   >>> c = Counter()                           # a new, empty counter
   >>> c = Counter('gallahad')                 # a new counter from an iterable
   >>> c = Counter({'red': 4, 'blue': 2})      # a new counter from a mapping
   >>> c = Counter(cats=4, dogs=8)             # a new counter from keyword args

   계수기 객체는 누락된 항목에 대해 "KeyError"를 발생시키는 대신 0을
   반환한다는 점을 제외하고 딕셔너리 인터페이스를 갖습니다:

   >>> c = Counter(['eggs', 'ham'])
   >>> c['bacon']                              # count of a missing element is zero
   0

   개수를 0으로 설정해도 계수기에서 요소가 제거되지 않습니다. 완전히
   제거하려면 "del"을 사용하십시오:

   >>> c['sausage'] = 0                        # counter entry with a zero count
   >>> del c['sausage']                        # del actually removes the entry

   Added in version 3.1.

   버전 3.7에서 변경: "dict" 서브 클래스로서, "Counter"는 삽입 순서를
   기억하는 기능을 상속했습니다. *Counter* 객체에 대한 수학 연산도 순
   서를 유지합니다. 결과는 요소가 왼쪽 피연산자에서 처음 발견된 순서로
   먼저 나열된 후 오른쪽 피연산자에서 새로 발견되는 순서로 나열되는 순
   서를 따릅니다.

   계수기 객체는 모든 딕셔너리에서 사용할 수 있는 메서드 이외의 추가
   메서드를 지원합니다:

   elements()

      개수만큼 반복되는 요소에 대한 이터레이터를 반환합니다. 요소는 처
      음 발견되는 순서대로 반환됩니다. 요소의 개수가 1보다 작으면
      "elements()"는 이를 무시합니다.

      >>> c = Counter(a=4, b=2, c=0, d=-2)
      >>> sorted(c.elements())
      ['a', 'a', 'a', 'a', 'b', 'b']

   most_common(n=None)

      *n* 개의 가장 흔한 요소와 그 개수를 가장 흔한 것부터 가장 적은
      것 순으로 나열한 리스트를 반환합니다. *n*이 생략되거나 "None"이
      면, "most_common()"은 계수기의 *모든* 요소를 반환합니다. 개수가
      같은 요소는 처음 발견된 순서를 유지합니다:

      >>> Counter('abracadabra').most_common(3)
      [('a', 5), ('b', 2), ('r', 2)]

   subtract(**kwargs)
   subtract(iterable, /, **kwargs)
   subtract(mapping, /, **kwargs)

      *이터러블*이나 다른 *매핑* (또는 계수기)으로부터 온 요소들을 뺍
      니다. "dict.update()"와 비슷하지만 교체하는 대신 개수를 뺍니다.
      입력과 출력 모두 0이나 음수일 수 있습니다.

      >>> c = Counter(a=4, b=2, c=0, d=-2)
      >>> d = Counter(a=1, b=2, c=3, d=4)
      >>> c.subtract(d)
      >>> c
      Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})

      Added in version 3.2.

   total()

      Compute the sum of the counts.

      >>> c = Counter(a=10, b=5, c=0)
      >>> c.total()
      15

      Added in version 3.10.

   일반적인 딕셔너리 메서드를 "Counter" 객체에 사용할 수 있습니다만,
   두 메서드는 계수기에서 다르게 동작합니다.

   fromkeys(iterable)

      이 클래스 메서드는 "Counter" 객체에 구현되지 않았습니다.

   update(**kwargs)
   update(iterable, /, **kwargs)
   update(mapping, /, **kwargs)

      요소는 *이터러블*에서 세거나 다른 *매핑*(또는 계수기)에서 더해집
      니다. "dict.update()"와 비슷하지만, 교체하는 대신 더합니다. 또한
      , *이터러블*은 "(key, value)" 쌍의 시퀀스가 아닌, 요소의 시퀀스
      일 것으로 기대합니다.

Counters support rich comparison operators for equality, subset, and
superset relationships: "==", "!=", "<", "<=", ">", ">=". All of those
tests treat missing elements as having zero counts so that
"Counter(a=1) == Counter(a=1, b=0)" returns true.

버전 3.10에서 변경: Rich comparison operations were added.

버전 3.10에서 변경: In equality tests, missing elements are treated as
having zero counts. Formerly, "Counter(a=3)" and "Counter(a=3, b=0)"
were considered distinct.

"Counter" 객체로 작업하는 일반적인 패턴:

   c.total()                       # 모든 개수의 총합
   c.clear()                       # 모든 개수를 재설정합니다
   list(c)                         # 고유한 요소들의 리스트
   set(c)                          # 집합으로 변환합니다
   dict(c)                         # 일반 딕셔너리로 변환합니다
   c.items()                       # (elem, cnt) 쌍을 액세스합니다
   Counter(dict(list_of_pairs))    # (elem, cnt) 쌍의 리스트를 변환합니다
   c.most_common()[:-n-1:-1]       # 가장 드문 n 개의 요소
   +c                              # 0과 음의 개수를 제거합니다

"Counter" 객체를 결합하여 멀티 셋(multiset, 개수가 0보다 큰 계수기)을
생성하는 여러 수학 연산이 제공됩니다. 더하기와 빼기는 해당 요소의 개수
를 더 하거나 빼서 계수기를 결합합니다. 교집합(intersection)과 합집합
(union)은 해당 개수의 최솟값과 최댓값을 반환합니다. 동등성과 포함은 해
당 개수를 비교합니다. 각 연산은 부호 있는 개수를 입력으로 받을 수 있지
만, 출력은 개수가 0 이하면 결과에서 제외합니다.

   >>> c = Counter(a=3, b=1)
   >>> d = Counter(a=1, b=2)
   >>> c + d                       # 두 계수기를 합합니다:  c[x] + d[x]
   Counter({'a': 4, 'b': 3})
   >>> c - d                       # 뺍니다 (양의 개수만 유지합니다)
   Counter({'a': 2})
   >>> c & d                       # 교집합:  min(c[x], d[x])
   Counter({'a': 1, 'b': 1})
   >>> c | d                       # 합집합:  max(c[x], d[x])
   Counter({'a': 3, 'b': 2})
   >>> c == d                      # 동등성:  c[x] == d[x]
   False
   >>> c <= d                      # 포함:  c[x] <= d[x]
   False

단항 덧셈과 뺄셈은 빈 계수기를 더하거나 빈 계수기를 빼는 것의 줄임 표
현입니다.

>>> c = Counter(a=2, b=-4)
>>> +c
Counter({'a': 2})
>>> -c
Counter({'b': 4})

Added in version 3.3: 단항 플러스, 단항 마이너스 및 제자리 멀티 셋 연
산에 대한 지원이 추가되었습니다.

참고:

  계수기는 주로 양의 정수로 작동하여 횟수를 나타내도록 설계되었습니다;
  그러나, 다른 형이나 음수 값이 필요한 사용 사례를 불필요하게 배제하지
  않도록 주의를 기울였습니다. 이러한 사용 사례에 도움이 되도록, 이 절
  은 최소 범위와 형 제약 사항을 설명합니다.

  * "Counter" 클래스 자체는 키와 값에 제한이 없는 딕셔너리 서브 클래스
    입니다. 값은 개수를 나타내는 숫자로 의도되었지만, 값 필드에 어떤
    것이든 저장할 *수* 있습니다.

  * "most_common()" 메서드는 값에 대해 순서만을 요구합니다.

  * "c[key] += 1"과 같은 제자리 연산의 경우, 값 형은 덧셈과 뺄셈만 지
    원하면 됩니다. 따라서 분수(fractions), 부동 소수점(floats) 및 십진
    수(decimals)가 작동하고 음수 값이 지원됩니다. "update()"와
    "subtract()"에 대해서도 마찬가지인데, 입력과 출력 모두 음수와 0을
    허용합니다.

  * 멀티 셋(multiset) 메서드는 양의 값에 대한 사용 사례를 위해서만 설
    계되었습니다. 입력은 음수이거나 0일 수 있지만, 양수 값을 갖는 출력
    만 만들어집니다. 형 제한은 없지만, 값 형은 더하기, 빼기 및 비교를
    지원해야 합니다.

  * "elements()" 메서드는 정수 개수를 요구합니다. 0과 음수 개수는 무시
    합니다.

더 보기:

  * 스몰토크(Smalltalk)의 Bag 클래스.

  * Multisets에 대한 위키피디아 항목.

  * 예제가 포함된 C++ multisets 자습서.

  * 멀티 셋에 대한 수학 연산과 그 사용 사례에 대해서는, *Knuth,
    Donald. The Art of Computer Programming Volume II, Section 4.6.3,
    Exercise 19*를 참조하십시오.

  * 주어진 요소 집합에 대해 주어진 크기의 모든 서로 다른 멀티 셋을 열
    거하려면, "itertools.combinations_with_replacement()"를 참조하십시
    오:

       map(Counter, combinations_with_replacement('ABC', 2)) # --> AA AB AC BB BC CC


"deque" 객체
============

class collections.deque([iterable[, maxlen]])

   *iterable*의 데이터로 왼쪽에서 오른쪽으로 ("append()"를 사용해서)
   초기화된 새 데크(deque) 객체를 반환합니다. *iterable*을 지정하지 않
   으면, 새 데크는 비어 있습니다.

   데크는 스택과 큐를 일반화 한 것입니다 (이름은 "deck"이라고 발음하며
   "double-ended queue"의 약자입니다). 데크는 스레드 안전하고 메모리
   효율적인 데크의 양쪽 끝에서의 추가(append)와 팝(pop)을 양쪽에서 거
   의 같은 *O*(1) 성능으로 지원합니다.

   "list" 객체는 유사한 연산을 지원하지만, 빠른 고정 길이 연산에 최적
   화되어 있으며, 하부 데이터 표현의 크기와 위치를 모두 변경하는
   "pop(0)"과 "insert(0, v)" 연산에 대해 *O*(*n*) 메모리 이동 비용이
   발생합니다.

   *maxlen*이 지정되지 않거나 "None"이면, 데크는 임의의 길이로 커질 수
   있습니다. 그렇지 않으면, 데크는 지정된 최대 길이로 제한됩니다. 일단
   제한된 길이의 데크가 가득 차면, 새 항목이 추가될 때, 해당하는 수의
   항목이 반대쪽 끝에서 삭제됩니다. 제한된 길이의 데크는 유닉스의
   "tail" 필터와 유사한 기능을 제공합니다. 또한 가장 최근 활동만 관심
   이 있는 트랜잭션과 기타 데이터 풀을 추적하는 데 유용합니다.

   deque 객체는 다음 메서드를 지원합니다:

   append(item, /)

      Add *item* to the right side of the deque.

   appendleft(item, /)

      Add *item* to the left side of the deque.

   clear()

      데크에서 모든 요소를 제거하고 길이가 0인 상태로 만듭니다.

   copy()

      데크의 얕은 복사본을 만듭니다.

      Added in version 3.5.

   count(value, /)

      Count the number of deque elements equal to *value*.

      Added in version 3.2.

   extend(iterable, /)

      iterable 인자에서 온 요소를 추가하여 데크의 오른쪽을 확장합니다.

   extendleft(iterable, /)

      *iterable*에서 온 요소를 추가하여 데크의 왼쪽을 확장합니다. 일련
      의 왼쪽 추가는 iterable 인자에 있는 요소의 순서를 뒤집는 결과를
      줍니다.

   index(value[, start[, stop]])

      Return the position of *value* in the deque (at or after index
      *start* and before index *stop*).  Returns the first match or
      raises "ValueError" if not found.

      Added in version 3.5.

   insert(index, value, /)

      Insert *value* into the deque at position *index*.

      삽입으로 인해 제한된 길이의 데크가 *maxlen* 이상으로 커지면,
      "IndexError"가 발생합니다.

      Added in version 3.5.

   pop()

      데크의 오른쪽에서 요소를 제거하고 반환합니다. 요소가 없으면,
      "IndexError"를 발생시킵니다.

   popleft()

      데크의 왼쪽에서 요소를 제거하고 반환합니다. 요소가 없으면,
      "IndexError"를 발생시킵니다.

   remove(value, /)

      *value*의 첫 번째 항목을 제거합니다. 찾을 수 없으면,
      "ValueError"를 발생시킵니다.

   reverse()

      데크의 요소들을 제자리에서 순서를 뒤집고 "None"을 반환합니다.

      Added in version 3.2.

   rotate(n=1, /)

      데크를 *n* 단계 오른쪽으로 회전합니다. *n*이 음수이면, 왼쪽으로
      회전합니다.

      데크가 비어 있지 않으면, 오른쪽으로 한 단계 회전하는 것은
      "d.appendleft(d.pop())"과 동등하고, 왼쪽으로 한 단계 회전하는 것
      은 "d.append(d.popleft())"와 동등합니다.

   데크 객체는 하나의 읽기 전용 어트리뷰트도 제공합니다:

   maxlen

      데크의 최대 크기 또는 제한이 없으면 "None".

      Added in version 3.1.

상기한 것들 외에도, 데크는 이터레이션, 피클링, "len(d)",
"reversed(d)", "copy.copy(d)", "copy.deepcopy(d)", "in" 연산자를 사용
한 멤버십 검사 및 첫 번째 요소를 액세스하는 "d[0]"과 같은 서브 스크립
트 참조를 지원합니다. 인덱스를 사용하는 액세스는 양쪽 끝에서는 *O*(1)
이지만 중간에서는 *O*(*n*) 으로 느려집니다. 빠른 무작위 액세스를 위해
서는 대신 리스트를 사용하십시오.

버전 3.5부터, 데크는 "__add__()", "__mul__()" 및 "__imul__()"을 지원합
니다.

예:

   >>> from collections import deque
   >>> d = deque('ghi')                 # 세 항목의 새 데크를 만듭니다
   >>> for elem in d:                   # 데크의 요소들을 이터레이트 합니다
   ...     print(elem.upper())
   G
   H
   I

   >>> d.append('j')                    # 오른쪽에 새 항목을 추가합니다
   >>> d.appendleft('f')                # 왼쪽에 새 항목을 추가합니다
   >>> d                                # 데크의 표현을 보여줍니다
   deque(['f', 'g', 'h', 'i', 'j'])

   >>> d.pop()                          # 가장 오른쪽의 항목을 제거하고 반환합니다
   'j'
   >>> d.popleft()                      # 가장 왼쪽의 항목을 제거하고 반환합니다
   'f'
   >>> list(d)                          # 데크의 내용을 나열합니다
   ['g', 'h', 'i']
   >>> d[0]                             # 가장 왼쪽의 항목을 들여다봅니다
   'g'
   >>> d[-1]                            # 가장 오른쪽의 항목을 들여다봅니다
   'i'

   >>> list(reversed(d))                # 데크의 내용을 역순으로 나열합니다
   ['i', 'h', 'g']
   >>> 'h' in d                         # 데크를 검색합니다
   True
   >>> d.extend('jkl')                  # 여러 요소를 한 번에 추가합니다
   >>> d
   deque(['g', 'h', 'i', 'j', 'k', 'l'])
   >>> d.rotate(1)                      # 오른쪽으로 회전합니다
   >>> d
   deque(['l', 'g', 'h', 'i', 'j', 'k'])
   >>> d.rotate(-1)                     # 왼쪽으로 회전합니다
   >>> d
   deque(['g', 'h', 'i', 'j', 'k', 'l'])

   >>> deque(reversed(d))               # 역순으로 새 데크를 만듭니다
   deque(['l', 'k', 'j', 'i', 'h', 'g'])
   >>> d.clear()                        # 데크를 비웁니다
   >>> d.pop()                          # 빈 데크에서는 pop 할 수 없습니다
   Traceback (most recent call last):
       File "<pyshell#6>", line 1, in -toplevel-
           d.pop()
   IndexError: pop from an empty deque

   >>> d.extendleft('abc')              # extendleft() 는 입력의 순서를 뒤집습니다
   >>> d
   deque(['c', 'b', 'a'])


"deque" 조리법
--------------

이 절은 데크로 작업하는 다양한 접근 방식을 보여줍니다.

제한된 길이의 데크는 유닉스의 "tail" 필터와 유사한 기능을 제공합니다:

   def tail(filename, n=10):
       '파일의 마지막 n 줄을 반환합니다'
       with open(filename) as f:
           return deque(f, n)

데크를 사용하는 또 다른 접근법은 오른쪽에 추가하고 왼쪽에서 팝 하여 최
근에 추가된 요소의 시퀀스를 유지하는 것입니다:

   def moving_average(iterable, n=3):
       # moving_average([40, 30, 50, 46, 39, 44]) --> 40.0 42.0 45.0 43.0
       # https://en.wikipedia.org/wiki/Moving_average
       it = iter(iterable)
       d = deque(itertools.islice(it, n-1))
       d.appendleft(0)
       s = sum(d)
       for elem in it:
           s += elem - d.popleft()
           d.append(elem)
           yield s / n

라운드 로빈 스케줄러(round-robin scheduler)는 "deque"에 저장된 입력 이
터레이터로 구현할 수 있습니다. 위치 0에 있는 활성 이터레이터에서 값이
산출됩니다. 그 이터레이터가 소진되면, "popleft()"로 제거할 수 있습니다
; 그렇지 않으면, "rotate()" 메서드로 끝으로 보내 순환할 수 있습니다:

   def roundrobin(*iterables):
       "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
       iterators = deque(map(iter, iterables))
       while iterators:
           try:
               while True:
                   yield next(iterators[0])
                   iterators.rotate(-1)
           except StopIteration:
               # 소진된 이터레이터를 제거합니다.
               iterators.popleft()

"rotate()" 메서드는 "deque" 슬라이싱과 삭제를 구현하는 방법을 제공합니
다. 예를 들어, "del d[n]"의 순수 파이썬 구현은 팝 될 요소의 위치를 잡
기 위해 "rotate()" 메서드에 의존합니다:

   def delete_nth(d, n):
       d.rotate(-n)
       d.popleft()
       d.rotate(n)

"deque" 슬라이싱을 구현하려면, 대상 요소를 데크의 왼쪽으로 가져오기 위
해 "rotate()"를 적용하는 유사한 접근법을 사용하십시오. "popleft()"로
이전 항목을 제거하고, "extend()"로 새 항목을 추가한 다음, 회전을 되돌
립니다. 이 접근 방식에 약간의 변형을 가하면, "dup", "drop", "swap",
"over", "pick", "rot" 및 "roll"과 같은 Forth 스타일 스택 조작을 쉽게
구현할 수 있습니다.


"defaultdict" 객체
==================

class collections.defaultdict(default_factory=None, /, **kwargs)
class collections.defaultdict(default_factory, mapping, /, **kwargs)
class collections.defaultdict(default_factory, iterable, /, **kwargs)

   새 딕셔너리류 객체를 반환합니다. "defaultdict"는 내장 "dict" 클래스
   의 서브 클래스입니다. 하나의 메서드를 재정의하고 하나의 쓰기 가능한
   인스턴스 변수를 추가합니다. 나머지 기능은 "dict" 클래스와 같고 여기
   에 설명하지 않습니다.

   첫 번째 인자는 "default_factory" 어트리뷰트의 초깃값을 제공합니다;
   기본값은 "None"입니다. 나머지 모든 인자는 키워드 인자를 포함하여
   "dict" 생성자에 전달될 때와 마찬가지로 취급됩니다.

   "defaultdict" 객체는 표준 "dict" 연산 외에도 다음 메서드를 지원합니
   다:

   __missing__(key, /)

      "default_factory" 어트리뷰트가 "None"이면, *key*를 인자로 사용하
      는 "KeyError" 예외가 발생합니다.

      "default_factory"가 "None"이 아니면, 주어진 *key*에 대한 기본값
      을 제공하기 위해 인자 없이 호출되며, 반환 값은 *key*로 딕셔너리
      에 삽입되고 반환됩니다.

      "default_factory"를 호출할 때 예외가 발생하면 이 예외는 변경되지
      않고 전파됩니다.

      이 메서드는 요청된 키를 찾을 수 없을 때 "dict" 클래스의
      "__getitem__()" 메서드에 의해 호출됩니다; 이것이 반환하거나 발생
      시키는 모든 것은, "__getitem__()"이 반환하거나 발생시킵니다.

      "__missing__()"은 "__getitem__()" 이외의 어떤 연산에서도 호출되
      지 *않음*에 유의하십시오. 이것은 "get()"이 일반 딕셔너리와 마찬
      가지로 "default_factory"를 사용하지 않고 "None"을 기본값으로 반
      환한다는 것을 의미합니다.

   "defaultdict" 객체는 다음 인스턴스 변수를 지원합니다:

   default_factory

      This attribute is used by the "__missing__()" method; it is
      initialized from the first argument to the constructor, if
      present, or to "None", if absent.

   버전 3.9에서 변경: **PEP 584**에 지정된, 병합("|")과 업데이트("|=")
   연산자가 추가되었습니다.


"defaultdict" 예
----------------

"list"를 "default_factory"로 사용하면, 키-값 쌍의 시퀀스를 리스트의 딕
셔너리로 쉽게 그룹화 할 수 있습니다:

>>> 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])]

When each key is encountered for the first time, it is not already in
the mapping; so an entry is automatically created using the
"default_factory" function which returns an empty "list".  The
"list.append()" operation then attaches the value to the new list.
When keys are encountered again, the look-up proceeds normally
(returning the list for that key) and the "list.append()" operation
adds another value to the list. This technique is simpler and faster
than an equivalent technique using "dict.setdefault()":

>>> d = {}
>>> for k, v in s:
...     d.setdefault(k, []).append(v)
...
>>> sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

"default_factory"를 "int"로 설정하면 "defaultdict"를 세는(counting) 데
유용하게 사용할 수 있습니다 (다른 언어의 백(bag)이나 멀티 셋(multiset)
처럼):

>>> s = 'mississippi'
>>> d = defaultdict(int)
>>> for k in s:
...     d[k] += 1
...
>>> sorted(d.items())
[('i', 4), ('m', 1), ('p', 2), ('s', 4)]

글자가 처음 발견될 때, 매핑에서 누락되었으므로, "default_factory" 함수
는 "int()"를 호출하여 기본 계수 0을 제공합니다. 증분 연산은 각 문자의
개수를 쌓아나갑니다.

항상 0을 반환하는 함수 "int()"는 상수 함수의 특별한 경우일 뿐입니다.
상수 함수를 만드는 더 빠르고 유연한 방법은 (단지 0이 아니라) 임의의 상
숫값을 제공 할 수 있는 람다 함수를 사용하는 것입니다:

>>> def constant_factory(value):
...     return lambda: value
...
>>> d = defaultdict(constant_factory('<missing>'))
>>> d.update(name='John', action='ran')
>>> '%(name)s %(action)s to %(object)s' % d
'John ran to <missing>'

"default_factory"를 "set"으로 설정하면, "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})]


이름있는 필드를 가진 튜플을 위한 "namedtuple()" 팩토리 함수
===========================================================

네임드 튜플은 튜플의 각 위치에 의미를 부여하고 더 읽기 쉽고 스스로 설
명하는 코드를 만들도록 합니다. 일반 튜플이 사용되는 곳이라면 어디에서
나 사용할 수 있으며, 위치 인덱스 대신 이름으로 필드에 액세스하는 기능
을 추가합니다.

collections.namedtuple(typename, field_names, *, rename=False, defaults=None, module=None)

   *typename*이라는 이름의 새 튜플 서브 클래스를 반환합니다. 새로운 서
   브 클래스는 인덱싱되고 이터러블일 뿐만 아니라 어트리뷰트 조회로 액
   세스 할 수 있는 필드를 갖는 튜플류 객체를 만드는 데 사용됩니다. 서
   브 클래스의 인스턴스에는 유용한 독스트링(*typename*과 *field_names*
   를 포함합니다)과 튜플 내용을 "name=value" 형식으로 나열하는 유용한
   "__repr__()" 메서드가 있습니다.

   *field_names*는 "['x', 'y']"와 같은 문자열의 시퀀스입니다. 또는,
   *field_names*는 각 필드명이 공백 및/또는 쉼표로 구분된 단일 문자열
   일 수 있습니다, 예를 들어 "'x y'"나 "'x, y'".

   밑줄로 시작하는 이름을 제외한 모든 유효한 파이썬 식별자를 필드명에
   사용할 수 있습니다. 유효한 식별자는 글자, 숫자 및 밑줄로 구성되지만
   , 숫자나 밑줄로 시작하지 않으며 *class*, *for*, *return*, *global*,
   *pass* 또는 *raise*와 같은 "keyword"일 수 없습니다.

   *rename*이 참이면, 유효하지 않은 필드명은 위치 이름으로 자동 대체됩
   니다. 예를 들어, "['abc', 'def', 'ghi', 'abc']"는 "['abc', '_1',
   'ghi', '_3']"으로 변환되어 키워드 "def"와 중복된 필드명 "abc"를 제
   거합니다.

   *defaults*는 "None"이나 기본값의 *이터러블* 일 수 있습니다. 기본값
   이 있는 필드는 기본값이 없는 필드 뒤에 와야 하므로, *defaults*는 가
   장 오른쪽의 매개 변수에 적용됩니다. 예를 들어, field_names가 "['x',
   'y', 'z']"이고 defaults가 "(1, 2)"이면 "x"는 필수 인자이고, "y"의
   기본값은 "1", "z"의 기본값은 "2"입니다.

   *module*이 정의되면, 네임드 튜플의 "__module__" 어트리뷰트가 해당
   값으로 설정됩니다.

   네임드 튜플 인스턴스에는 인스턴스 별 딕셔너리가 없어서, 가볍고 일반
   튜플보다 더 많은 메모리가 필요하지 않습니다.

   피클링을 지원하려면, 네임드 튜플 클래스를 *typename*과 일치하는 변
   수에 대입해야 합니다.

   버전 3.1에서 변경: *rename*에 대한 지원이 추가되었습니다.

   버전 3.6에서 변경: *verbose*와 *rename* 매개 변수는 키워드 전용 인
   자가 되었습니다.

   버전 3.6에서 변경: *module* 매개 변수를 추가했습니다.

   버전 3.7에서 변경: *verbose* 매개 변수와 "_source" 어트리뷰트를 제
   거했습니다.

   버전 3.7에서 변경: *defaults* 매개 변수와 "_field_defaults" 어트리
   뷰트가 추가되었습니다.

   >>> # Basic example
   >>> Point = namedtuple('Point', ['x', 'y'])
   >>> p = Point(11, y=22)     # 위치와 키워드 인자로 인스턴스를 만듭니다
   >>> p[0] + p[1]             # 일반 튜플 (11, 22) 처럼 인덱싱할 수 있습니다
   33
   >>> x, y = p                # 일반 튜플처럼 언팩합니다
   >>> x, y
   (11, 22)
   >>> p.x + p.y               # 필드는 이름으로도 액세스할 수 있습니다
   33
   >>> p                       # name=value 스타일의 가독성 있는 __repr__
   Point(x=11, y=22)

네임드 튜플은 "csv" 나 "sqlite3" 모듈이 반환한 결과 튜플에 필드 이름을
할당하는 데 특히 유용합니다:

   EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')

   import csv
   for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))):
       print(emp.name, emp.title)

   import sqlite3
   conn = sqlite3.connect('/companydata')
   cursor = conn.cursor()
   cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
   for emp in map(EmployeeRecord._make, cursor.fetchall()):
       print(emp.name, emp.title)

튜플에서 상속된 메서드 외에도 네임드 튜플은 세 가지 추가 메서드와 두
가지 어트리뷰트를 지원합니다. 필드 이름과의 충돌을 방지하기 위해, 메서
드와 어트리뷰트 이름은 밑줄로 시작합니다.

classmethod somenamedtuple._make(iterable, /)

   기존 시퀀스나 이터러블로 새 인스턴스를 만드는 클래스 메서드.

      >>> t = [11, 22]
      >>> Point._make(t)
      Point(x=11, y=22)

somenamedtuple._asdict()

   필드 이름을 해당 값으로 매핑하는 새 "dict"를 반환합니다:

      >>> p = Point(x=11, y=22)
      >>> p._asdict()
      {'x': 11, 'y': 22}

   버전 3.1에서 변경: 일반 "dict" 대신 "OrderedDict"를 반환합니다.

   버전 3.8에서 변경: "OrderedDict" 대신 일반 "dict"를 반환합니다. 파
   이썬 3.7부터, 일반 딕셔너리의 순서가 유지되도록 보장합니다.
   "OrderedDict"의 추가 기능이 필요할 때, 제안하는 처방은 결과를 원하
   는 형으로 캐스트 하는 것입니다: "OrderedDict(nt._asdict())".

somenamedtuple._replace(**kwargs)

   지정된 필드들을 새로운 값으로 치환하는 네임드 튜플의 새 인스턴스를
   반환합니다:

      >>> p = Point(x=11, y=22)
      >>> p._replace(x=33)
      Point(x=33, y=22)

      >>> for partnum, record in inventory.items():
      ...     inventory[partnum] = record._replace(price=newprices[partnum], timestamp=time.now())

   Named tuples are also supported by generic function
   "copy.replace()".

   버전 3.13에서 변경: Raise "TypeError" instead of "ValueError" for
   invalid keyword arguments.

somenamedtuple._fields

   필드 이름을 나열하는 문자열의 튜플. 인트로스펙션과 기존 네임드 튜플
   에서 새로운 네임드 튜플 형을 만드는 데 유용합니다.

      >>> p._fields            # 필드 이름을 봅니다
      ('x', 'y')

      >>> Color = namedtuple('Color', 'red green blue')
      >>> Pixel = namedtuple('Pixel', Point._fields + Color._fields)
      >>> Pixel(11, 22, 128, 255, 0)
      Pixel(x=11, y=22, red=128, green=255, blue=0)

somenamedtuple._field_defaults

   필드 이름을 기본값으로 매핑하는 딕셔너리.

      >>> Account = namedtuple('Account', ['type', 'balance'], defaults=[0])
      >>> Account._field_defaults
      {'balance': 0}
      >>> Account('premium')
      Account(type='premium', balance=0)

이름이 문자열에 저장된 필드를 조회하려면 "getattr()" 함수를 사용하십시
오.:

>>> getattr(p, 'x')
11

딕셔너리를 네임드 튜플로 변환하려면 이중 애스터리스크 연산자를 사용하
십시오 (인자 목록 언 패킹에서 설명합니다).:

>>> d = {'x': 11, 'y': 22}
>>> Point(**d)
Point(x=11, y=22)

네임드 튜플은 일반적인 파이썬 클래스이므로, 서브 클래스를 사용하여 기
능을 쉽게 추가하거나 변경할 수 있습니다. 계산된 필드와 고정 너비 인쇄
포맷을 추가하는 방법은 다음과 같습니다:

   >>> class Point(namedtuple('Point', ['x', 'y'])):
   ...     __slots__ = ()
   ...     @property
   ...     def hypot(self):
   ...         return (self.x ** 2 + self.y ** 2) ** 0.5
   ...     def __str__(self):
   ...         return 'Point: x=%6.3f  y=%6.3f  hypot=%6.3f' % (self.x, self.y, self.hypot)

   >>> for p in Point(3, 4), Point(14, 5/7):
   ...     print(p)
   Point: x= 3.000  y= 4.000  hypot= 5.000
   Point: x=14.000  y= 0.714  hypot=14.018

위에 표시된 서브 클래스는 "__slots__"를 빈 튜플로 설정합니다. 이렇게
하면 인스턴스 딕셔너리 생성을 방지하여 메모리 요구 사항을 낮게 유지할
수 있습니다.

서브 클래싱은 저장된 새 필드를 추가하는 데는 유용하지 않습니다. 대신,
"_fields" 어트리뷰트로 새로운 네임드 튜플 형을 만드십시오:

>>> Point3D = namedtuple('Point3D', Point._fields + ('z',))

"__doc__" 필드에 직접 대입하여 독스트링을 사용자 정의할 수 있습니다:

>>> Book = namedtuple('Book', ['id', 'title', 'authors'])
>>> Book.__doc__ += ': Hardcover book in active collection'
>>> Book.id.__doc__ = '13-digit ISBN'
>>> Book.title.__doc__ = 'Title of first printing'
>>> Book.authors.__doc__ = 'List of authors sorted by last name'

버전 3.5에서 변경: 프로퍼티 독스트링이 쓰기 가능하게 되었습니다.

더 보기:

  * 네임드 튜플에 형 힌트를 추가하는 방법은 "typing.NamedTuple"을 참조
    하십시오. 이것은 "class" 키워드를 사용하는 우아한 표기법도 제공합
    니다:

       class Component(NamedTuple):
           part_number: int
           weight: float
           description: Optional[str] = None

  * 튜플 대신 하부 딕셔너리를 기반으로 하는 가변 이름 공간에 대해서는
    "types.SimpleNamespace()"를 참조하십시오.

  * "dataclasses" 모듈은 사용자 정의 클래스에 생성된 특수 메서드를 자
    동으로 추가하는 데코레이터와 함수를 제공합니다.


"OrderedDict" 객체
==================

순서 있는 딕셔너리는 일반 딕셔너리와 비슷하지만, 순서를 다루는 연산과
관련된 몇 가지 추가 기능이 있습니다. 내장 "dict" 클래스가 삽입 순서를
기억하는 기능을 얻었으므로 (이 새로운 동작은 파이썬 3.7에서 보장되었습
니다), 이제 덜 중요해졌습니다.

몇 가지 "dict"와의 차이점은 여전히 남아 있습니다:

* 일반 "dict"는 매핑 연산에 매우 적합하도록 설계되었습니다. 삽입 순서
  추적은 부차적입니다.

* "OrderedDict"는 순서를 바꾸는 연산에 적합하도록 설계되었습니다. 공간
  효율성, 이터레이션 속도 및 갱신 연산의 성능은 부차적입니다.

* "OrderedDict" 알고리즘은 "dict"보다 빈번한 순서 변경 연산을 더 잘 처
  리할 수 있습니다. 아래의 조리법에서 볼 수 있듯이, 이는 다양한 종류의
  LRU 캐시를 구현하는 데 적합합니다.

* "OrderedDict"의 동등 비교 연산은 순서의 일치를 확인합니다.

  A regular "dict" can emulate the order sensitive equality test with
  "p == q and all(k1 == k2 for k1, k2 in zip(p, q))".

* "OrderedDict"의 "popitem()" 메서드는 서명이 다릅니다. 어떤 항목을 팝
  할지는 지정하는 선택적 인자를 받아들입니다.

  A regular "dict" can emulate OrderedDict's "od.popitem(last=True)"
  with "d.popitem()" which is guaranteed to pop the rightmost (last)
  item.

  A regular "dict" can emulate OrderedDict's "od.popitem(last=False)"
  with "(k := next(iter(d)), d.pop(k))" which will return and remove
  the leftmost (first) item if it exists.

* "OrderedDict"에는 요소를 효율적으로 끝으로 재배치하는
  "move_to_end()" 메서드가 있습니다.

  A regular "dict" can emulate OrderedDict's "od.move_to_end(k,
  last=True)" with "d[k] = d.pop(k)" which will move the key and its
  associated value to the rightmost (last) position.

  A regular "dict" does not have an efficient equivalent for
  OrderedDict's "od.move_to_end(k, last=False)" which moves the key
  and its associated value to the leftmost (first) position.

* 파이썬 3.8 이전에는, "dict"에 "__reversed__()" 메서드가 없었습니다.

class collections.OrderedDict(**kwargs)
class collections.OrderedDict(mapping, /, **kwargs)
class collections.OrderedDict(iterable, /, **kwargs)

   딕셔너리 순서 재배치에 특화된 메서드가 있는 "dict" 서브 클래스의 인
   스턴스를 반환합니다.

   Added in version 3.1.

   popitem(last=True)

      순서 있는 딕셔너리의 "popitem()" 메서드는 (키, 값) 쌍을 반환하고
      제거합니다. *last*가 참이면 쌍이 LIFO (last-in, first-out - 후입
      선출) 순서로 반환되고, 거짓이면 FIFO (first-in, first-out - 선입
      선출) 순서로 반환됩니다.

   move_to_end(key, last=True)

      기존 *key*를 순서 있는 딕셔너리의 한쪽 끝으로 옮깁니다. *last*가
      참(기본값)이면 항목은 오른쪽 끝으로 이동하고, *last*가 거짓이면
      처음으로 이동합니다. *key*가 존재하지 않으면 "KeyError"가 발생합
      니다:

         >>> d = OrderedDict.fromkeys('abcde')
         >>> d.move_to_end('b')
         >>> ''.join(d)
         'acdeb'
         >>> d.move_to_end('b', last=False)
         >>> ''.join(d)
         'bacde'

      Added in version 3.2.

일반적인 매핑 메서드 외에도 순서 있는 딕셔너리는 "reversed()"를 사용하
는 역 이터레이션을 지원합니다.

"OrderedDict" 객체 간의 동등성(equality) 테스트는 순서를 고려하며 대략
"list(od1.items())==list(od2.items())"와 동등합니다.

"OrderedDict" 객체와 다른 "Mapping" 객체 간의 동등성 테스트는 일반 딕
셔너리처럼 순서를 고려하지 않습니다. 이 때문에 "OrderedDict" 객체를 일
반 딕셔너리가 사용되는 모든 곳에 대체 할 수 있습니다.

버전 3.5에서 변경: "OrderedDict"의 items, keys 및 values *뷰*는 이제
"reversed()"를 사용하는 역 이터레이션을 지원합니다.

버전 3.6에서 변경: **PEP 468**을 수락함에 따라, "OrderedDict" 생성자와
"update()" 메서드로 전달된 키워드 인자의 순서가 보존됩니다.

버전 3.9에서 변경: **PEP 584**에 지정된, 병합("|")과 업데이트("|=") 연
산자가 추가되었습니다.


"OrderedDict" 예제와 조리법
---------------------------

키가 *마지막에* 삽입된 순서를 기억하는 순서 있는 딕셔너리 변형을 만드
는 것은 간단합니다. 새 항목이 기존 항목을 덮어쓰면, 원래 삽입 위치가
변경되고 끝으로 이동합니다:

   class LastUpdatedOrderedDict(OrderedDict):
       '키가 마지막에 삽입된 순서로 항목을 저장합니다'

       def __setitem__(self, key, value):
           super().__setitem__(key, value)
           self.move_to_end(key)

"OrderedDict"는 "functools.lru_cache()"의 변형을 구현하는 데에도 유용
합니다:

   from collections import OrderedDict
   from time import time

   class TimeBoundedLRU:
       "오래된 항목을 무효화하고 새로 고치는 LRU 캐시."

       def __init__(self, func, maxsize=128, maxage=30):
           self.cache = OrderedDict()      # { args : (timestamp, result)}
           self.func = func
           self.maxsize = maxsize
           self.maxage = maxage

       def __call__(self, *args):
           if args in self.cache:
               self.cache.move_to_end(args)
               timestamp, result = self.cache[args]
               if time() - timestamp <= self.maxage:
                   return result
           result = self.func(*args)
           self.cache[args] = time(), result
           if len(self.cache) > self.maxsize:
               self.cache.popitem(last=False)
           return result

   class MultiHitLRUCache:
       """ 여러 번 요청될 때까지 결과 캐싱을
            지연시키는 LRU 캐시.

           일회성 요청으로 인해 LRU 캐시를 비우는 것을 방지하기 위해,
           요청이 두 번 이상 이루어질 때까지 개시하지 않습니다.

       """

       def __init__(self, func, maxsize=128, maxrequests=4096, cache_after=1):
           self.requests = OrderedDict()   # { uncached_key : request_count }
           self.cache = OrderedDict()      # { cached_key : function_result }
           self.func = func
           self.maxrequests = maxrequests  # 캐시되지 않은 요청의 최대 수
           self.maxsize = maxsize          # 저장된 반환값의 최대 수
           self.cache_after = cache_after

       def __call__(self, *args):
           if args in self.cache:
               self.cache.move_to_end(args)
               return self.cache[args]
           result = self.func(*args)
           self.requests[args] = self.requests.get(args, 0) + 1
           if self.requests[args] <= self.cache_after:
               self.requests.move_to_end(args)
               if len(self.requests) > self.maxrequests:
                   self.requests.popitem(last=False)
           else:
               self.requests.pop(args, None)
               self.cache[args] = result
               if len(self.cache) > self.maxsize:
                   self.cache.popitem(last=False)
           return result


"UserDict" 객체
===============

"UserDict" 클래스는 딕셔너리 객체를 감싸는 래퍼 역할을 합니다. 이 클래
스의 필요성은 "dict"에서 직접 서브 클래싱 할 수 있는 능력에 의해 부분
적으로 대체되었습니다; 그러나 하부 딕셔너리를 어트리뷰트로 액세스 할
수 있어서, 이 클래스를 사용하면 작업하기가 더 쉬울 수 있습니다.

class collections.UserDict(**kwargs)
class collections.UserDict(mapping, /, **kwargs)
class collections.UserDict(iterable, /, **kwargs)

   Class that simulates a dictionary.  The instance's contents are
   kept in a regular dictionary, which is accessible via the "data"
   attribute of "UserDict" instances.  If arguments are provided, they
   are used to initialize "data", like a regular dictionary.

   In addition to supporting the methods and operations of mappings,
   "UserDict" instances provide the following attribute:

   data

      "UserDict" 클래스의 내용을 저장하는 데 사용되는 실제 딕셔너리.


"UserList" 객체
===============

이 클래스는 리스트 객체를 둘러싸는 래퍼 역할을 합니다. 여러분 자신의
리스트류 클래스가 상속하고 기존 메서드를 재정의하거나 새로운 메서드를
추가할 수 있는 유용한 베이스 클래스입니다. 이런 식으로 리스트에 새로운
동작을 추가 할 수 있습니다.

이 클래스의 필요성은 "list"에서 직접 서브 클래싱할 수 있는 능력에 의해
부분적으로 대체되었습니다; 그러나 하부 리스트에 어트리뷰트로 액세스할
수 있어서, 이 클래스를 사용하면 작업하기가 더 쉬울 수 있습니다.

class collections.UserList([list])

   리스트를 시뮬레이트 하는 클래스. 인스턴스의 내용은 일반 리스트로 유
   지되며 "UserList" 인스턴스의 "data" 어트리뷰트를 통해 액세스 할 수
   있습니다. 인스턴스의 내용은 초기에 *list*의 사본으로 설정되며, 기본
   값은 빈 목록 "[]"입니다. *list*는 모든 이터러블일 수 있습니다, 예를
   들어 실제 파이썬 리스트나 "UserList" 객체.

   "UserList" 인스턴스는 가변 시퀀스의 메서드와 연산을 지원할 뿐만 아
   니라 다음 어트리뷰트를 제공합니다:

   data

      "UserList" 클래스의 내용을 저장하는 데 사용되는 실제 "list" 객체
      .

**서브 클래싱 요구 사항:** "UserList"의 서브 클래스는 인자가 없거나 하
나의 인자로 호출 할 수 있는 생성자를 제공해야 합니다. 새 시퀀스를 반환
하는 리스트 연산은 실제 구현 클래스의 인스턴스를 만들려고 시도합니다.
이를 위해, 데이터 소스로 사용되는 시퀀스 객체인 단일 매개 변수로 생성
자를 호출할 수 있다고 가정합니다.

파생 클래스가 이 요구 사항을 준수하고 싶지 않다면, 이 클래스에서 지원
하는 모든 특수 메서드를 재정의해야 합니다; 이때 제공해야 하는 메서드에
대한 정보는 소스를 참조하십시오.


"UserString" 객체
=================

"UserString" 클래스는 문자열 객체를 둘러싸는 래퍼 역할을 합니다. 이 클
래스의 필요성은 "str"에서 직접 서브 클래싱할 수 있는 능력에 의해 부분
적으로 대체되었습니다; 그러나 하부 문자열을 어트리뷰트로 액세스할 수
있어서, 이 클래스를 사용하면 작업하기가 더 쉬울 수 있습니다.

class collections.UserString(seq)

   문자열 객체를 시뮬레이트 하는 클래스. 인스턴스의 내용은 일반 문자열
   객체로 유지되며, "UserString" 인스턴스의 "data" 어트리뷰트를 통해
   액세스 할 수 있습니다. 인스턴스의 내용은 처음에 *seq*의 사본으로 설
   정됩니다. *seq* 인자는 내장 "str()" 함수를 사용하여 문자열로 변환
   할 수 있는 모든 객체가 될 수 있습니다.

   "UserString" 인스턴스는 문자열의 메서드와 연산을 지원할 뿐만 아니라
   다음과 같은 어트리뷰트를 제공합니다:

   data

      "UserString" 클래스의 내용을 저장하는 데 사용되는 실제 "str" 객
      체.

   버전 3.5에서 변경: 새로운 메서드 "__getnewargs__", "__rmod__",
   "casefold", "format_map", "isprintable" 및 "maketrans".
