# `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과 음의 개수를 제거합니다

Several mathematical operations are provided for combining `Counter` objects to produce multisets (counters that have counts greater than zero). Addition and subtraction combine counters by adding or subtracting the counts of corresponding elements. Intersection and union return the minimum and maximum of corresponding counts. Symmetric difference returns the difference between the maximum and minimum of the corresponding counts. Equality and inclusion compare corresponding counts. Each operation can accept inputs with signed counts, but the output will exclude results with counts of zero or below.

    >>> c = Counter(a=3, b=1)
    >>> d = Counter(a=1, b=2)
    >>> c + d                       # add two counters together:  c[x] + d[x]
    Counter({'a': 4, 'b': 3})
    >>> c - d                       # subtract (keeping only positive counts)
    Counter({'a': 2})
    >>> c & d                       # intersection:  min(c[x], d[x])
    Counter({'a': 1, 'b': 1})
    >>> c | d                       # union:  max(c[x], d[x])
    Counter({'a': 3, 'b': 2})
    >>> c ^ d                       # max(c[x], d[x]) - min(c[x], d[x])
    Counter({'a': 2, 'b': 1})
    >>> c == d                      # equality:  c[x] == d[x]
    False
    >>> c <= d                      # inclusion:  c[x] <= d[x]
    False

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

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

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

Added in version 3.15: Added support for the symmetric difference multiset operation, `c ^ d`.

참고

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

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

    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([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):
        'Store items in the order that the keys were last updated.'

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