# `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([iterable-or-mapping])

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

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

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

  subtract([iterable-or-mapping])

    이터러블이나 다른 매핑 (또는 계수기)으로부터 온 요소들을 뺍니다. `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([iterable-or-mapping])

    요소는 이터러블에서 세거나 다른 매핑(또는 계수기)에서 더해집니다. `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(x)

    데크의 오른쪽에 x를 추가합니다.

  appendleft(x)

    데크의 왼쪽에 x를 추가합니다.

  clear()

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

  copy()

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

    Added in version 3.5.

  count(x)

    x 와 같은 데크 요소의 수를 셉니다.

    Added in version 3.2.

  extend(iterable)

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

  extendleft(iterable)

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

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

    데크에 있는 x의 위치를 반환합니다 (인덱스 start 또는 그 이후, 그리고 인덱스 stop 이전). 첫 번째 일치를 반환하거나 찾을 수 없으면 `ValueError`를 발생시킵니다.

    Added in version 3.5.

  insert(i, x)

    x를 데크의 i 위치에 삽입합니다.

    삽입으로 인해 제한된 길이의 데크가 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, /[, ...])

  새 딕셔너리류 객체를 반환합니다. `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

    이 어트리뷰트는 `__missing__()` 메서드에서 사용됩니다; 생성자의 첫 번째 인자가 있으면 그것으로, 없으면 `None`으로 초기화됩니다.

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

각 키가 처음 발견될 때, 아직 매핑에 있지 않게 됩니다; 그래서 `default_factory` 함수를 사용하여 항목이 자동으로 만들어지는데, 빈 `list`를 반환합니다. 그런 다음 `list.append()` 연산이 값을 새 리스트에 추가합니다. 키를 다시 만나면, 조회가 정상적으로 진행되고 (해당 키의 리스트를 반환합니다), `list.append()` 연산은 다른 값을 리스트에 추가합니다. 이 기법은 `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([items])

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

  Added in version 3.1.

  popitem(last=True)

    순서 있는 딕셔너리의 `popitem()` 메서드는 (키, 값) 쌍을 반환하고 제거합니다. last가 참이면 쌍이 LIFO 순서로 반환되고, 거짓이면 FIFO 순서로 반환됩니다.

  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([initialdata])

  딕셔너리를 시뮬레이트 하는 클래스. 인스턴스의 내용은 일반 딕셔너리에 보관되며, `UserDict` 인스턴스의 `data` 어트리뷰트를 통해 액세스 할 수 있습니다. initialdata가 제공되면 `data`는 그 내용으로 초기화됩니다; initialdata에 대한 참조는 유지되지 않아서, 다른 용도로 사용할 수 있습니다.

  `UserDict` 인스턴스는 매핑의 메서드와 연산을 지원할 뿐만 아니라, 다음과 같은 어트리뷰트를 제공합니다:

  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`.