# `shelve` — 파이썬 객체 지속성

소스 코드: Lib/shelve.py

“쉘프(shelf)”는 영속적인(persistent) 딕셔너리류 객체입니다. “dbm” 데이터베이스와의 차이점은 쉘프의 값(키가 아닙니다!)이 사실상 임의의 파이썬 객체일 수 있다는 것입니다 — `pickle` 모듈에서 처리할 수 있는 모든 것입니다. 여기에는 대부분의 클래스 인스턴스, 재귀적 데이터형 및 많은 공유 서브 객체를 포함하는 객체가 포함됩니다. 키는 일반 문자열입니다.

shelve.open(filename, flag='c', protocol=None, writeback=False)

  영속적 딕셔너리를 엽니다. 지정된 filename은 하부 데이터베이스의 기본 파일명입니다. 부작용으로, 확장명이 파일명에 추가될 수 있으며 여러 개의 파일이 만들어질 수 있습니다. 기본적으로, 하부 데이터베이스 파일은 읽기와 쓰기 용으로 열립니다. 선택적 flag 매개 변수는 `dbm.open()`의 flag 매개 변수와 같게 해석됩니다.

  기본적으로, 값을 직렬화하는 데 `pickle.DEFAULT_PROTOCOL`로 생성된 피클이 사용됩니다. 피클 프로토콜의 버전은 protocol 매개 변수로 지정할 수 있습니다.

  파이썬 의미론 때문에, 쉘프는 가변 영속 딕셔너리 항목이 언제 수정되는지 알 수 없습니다. 기본적으로 수정된 객체는 쉘프에 대입될 때만 기록됩니다 (예제를 참조하십시오). 선택적인 writeback 매개 변수가 `True`로 설정되면, 액세스 된 모든 항목도 메모리에 캐시 되고, `sync()`와 `close()`가 호출될 때 다시 기록됩니다; 이것은 영속 딕셔너리의 가변 항목을 변경하는 것을 더 수월하게 만들지만, 많은 항목이 액세스 되면, 캐시를 위해 막대한 양의 메모리를 소비할 수 있으며, 액세스 된 모든 항목을 다시 기록하기 때문에 닫기 연산이 매우 느려질 수 있습니다 (어떤 액세스 된 항목이 가변인지, 어떤 것이 실제로 변경되었는지를 판별할 방법이 없습니다).

  버전 3.10에서 변경: `pickle.DEFAULT_PROTOCOL` is now used as the default pickle protocol.

  버전 3.11에서 변경: Accepts path-like object for filename.

  참고

  쉘프가 자동으로 닫히는 것에 의지하지 마십시오; 더는 필요 없을 때 `close()`를 명시적으로 호출하거나, `shelve.open()`을 컨텍스트 관리자로 사용하십시오:

      with shelve.open('spam') as db:
          db['eggs'] = 'eggs'

경고

`shelve` 모듈은 `pickle`로 뒷받침되기 때문에, 신뢰할 수 없는 소스에서 쉘프를 로드하는 것은 안전하지 않습니다. 피클과 마찬가지로, 쉘프를 로드하면 임의의 코드를 실행할 수 있습니다.

쉘프 객체는 딕셔너리에서 지원하는 대부분의 메서드와 연산을 지원합니다 (복사, 생성자 및 연산자 `|`와 `|=`는 제외합니다). 이것은 딕셔너리 기반 스크립트에서 영속적인 저장소를 요구하는 것으로의 전환을 쉽게 만듭니다.

두 가지 추가 메서드가 지원됩니다:

Shelf.sync()

  writeback을 `True`로 설정하여 쉘프를 열었으면, 캐시의 모든 항목을 다시 기록합니다. 또한, 적절하다면, 캐시를 비우고 디스크 상의 영속 딕셔너리를 동기화합니다. `close()`로 쉘프를 닫을 때 자동으로 호출됩니다.

Shelf.close()

  영구 딕셔너리 객체를 동기화하고 닫습니다. 닫힌 쉘프에 대한 연산은 `ValueError`로 실패합니다.

더 보기

널리 지원되는 저장 형식과 기본 딕셔너리의 속도를 갖춘 Persistent dictionary recipe

## 제약 사항

- 사용되는 데이터베이스 패키지의 선택(가령 `dbm.ndbm`이나 `dbm.gnu`)은 어떤 인터페이스가 사용 가능한지에 따라 다릅니다. 따라서 `dbm`을 사용하여 데이터베이스를 직접 여는 것은 안전하지 않습니다. 또한, 데이터베이스는 (불행히도) `dbm`이 사용된다면 그것의 제약이 적용됩니다 — 이것은 데이터베이스에 저장되는 객체(의 피클 된 표현이)가 상당히 작아야 하며, 드물긴 하지만 키 충돌로 인해 데이터베이스가 업데이트를 거부할 수 있음을 뜻합니다.

- `shelve` 모듈은 쉘브된 객체에 대한 동시성(concurrent) 읽기/쓰기 액세스를 지원하지 않습니다. (여러 동시적인 읽기 액세스는 안전합니다.) 어떤 프로그램이 쓰기 용으로 쉘프를 열고 있으면, 다른 어떤 프로그램도 읽기나 쓰기 용으로 열지 않아야 합니다. 유닉스 파일 잠금을 이 문제를 해결하는 데 사용할 수 있지만, 이것은 유닉스 버전마다 다르며 사용된 데이터베이스 구현에 대한 지식이 필요합니다.

- On macOS `dbm.ndbm` can silently corrupt the database file on updates, which can cause hard crashes when trying to read from the database.

class shelve.Shelf(dict, protocol=None, writeback=False, keyencoding='utf-8')

  dict 객체에 피클 된 값을 저장하는 `collections.abc.MutableMapping`의 서브 클래스.

  기본적으로, 값을 직렬화하는 데 `pickle.DEFAULT_PROTOCOL`로 생성된 피클이 사용됩니다. 피클 프로토콜의 버전은 protocol 매개 변수로 지정할 수 있습니다. 피클 프로토콜에 대한 설명은 `pickle` 설명서를 참조하십시오.

  writeback 매개 변수가 `True`이면, 객체는 액세스 된 모든 항목의 캐시를 보유하고 sync와 close 할 때 dict에 다시 씁니다. 이것은 가변 항목에 대한 자연스러운 연산을 허락하지만, 더 많은 메모리를 소비하고 sync와 close 연산이 오래 걸릴 수 있습니다.

  keyencoding 매개 변수는 하부 dict에 사용되기 전에 키를 인코딩하는 데 사용되는 인코딩입니다.

  `Shelf` 객체는 컨텍스트 관리자로 사용할 수도 있습니다. 이 경우 `with` 블록이 끝날 때 자동으로 닫힙니다.

  버전 3.2에서 변경: keyencoding 매개 변수가 추가되었습니다; 이전에는 키가 항상 UTF-8으로 인코딩되었습니다.

  버전 3.4에서 변경: 컨텍스트 관리자 지원 추가.

  버전 3.10에서 변경: `pickle.DEFAULT_PROTOCOL` is now used as the default pickle protocol.

class shelve.BsdDbShelf(dict, protocol=None, writeback=False, keyencoding='utf-8')

  `first()`, `next()`, `previous()`, `last()` 및 `set_location()` 메서드를 노출하는 `Shelf`의 서브 클래스. pybsddb의 제삼자 `bsddb` 모듈에서는 사용할 수 있지만 다른 데이터베이스 모듈에서는 사용할 수 없습니다. 생성자에 전달된 dict 객체는 이러한 메서드를 지원해야 합니다. 이것은 일반적으로 `bsddb.hashopen()`, `bsddb.btopen()` 또는 `bsddb.rnopen()` 중 하나를 호출하여 수행됩니다. 선택적 protocol, writeback 및 keyencoding 매개 변수는 `Shelf` 클래스와 같게 해석됩니다.

class shelve.DbfilenameShelf(filename, flag='c', protocol=None, writeback=False)

  딕셔너리류 객체 대신에 filename을 받아들이는 `Shelf`의 서브 클래스. 하부 파일은 `dbm.open()`을 사용하여 열립니다. 기본적으로, 파일은 읽기와 쓰기가 가능하도록 만들어지고 열립니다. 선택적 flag 매개 변수는 `open()` 기능과 같게 해석됩니다. 선택적 protocol과 writeback 매개 변수는 `Shelf` 클래스와 같게 해석됩니다.

## 예제

인터페이스를 요약하면 (`key`는 문자열입니다, `data`는 임의의 객체입니다):

    import shelve

    d = shelve.open(filename)  # 열기 -- 파일은 저수준 라이브러리에 의해 추가된 접미사를 얻을
                               # 수 있습니다

    d[key] = data              # 키에 데이터를 저장합니다 (기존 키를 사용하면 예전 데이터를
                               # 덮어씁니다)
    data = d[key]              # 키에서 데이터의 사본을 꺼냅니다 (그런 키가 없으면 KeyError를
                               # 발생시킵니다)
    del d[key]                 # 키에 저장된 데이터를 삭제합니다 (그런 키가 없으면 KeyError를
                               # 발생시킵니다)

    flag = key in d            # 키가 존재하면 참입니다
    klist = list(d.keys())     # 존재하는 모든 키의 리스트 (느립니다!)

    # d가 writeback=True 없이 열렸으므로, 주의하십시오:
    d['xx'] = [0, 1, 2]        # 이것은 예상대로 작동합니다, 하지만...
    d['xx'].append(3)          # *이것은 그렇지 않습니다!* -- d['xx']는 여전히 [0, 1, 2]입니다!

    # writeback=True 없이 열린 d에서는, 신중하게 코딩해야 합니다:
    temp = d['xx']             # 사본을 꺼냅니다
    temp.append(5)             # 사본을 수정합니다
    d['xx'] = temp             # 영속적으로 만들기 위해, 사본을 다시 저장합니다

    # 또는, d=shelve.open(filename,writeback=True)는 단지 d['xx'].append(5)로
    # 코딩해도 기대한 대로 동작하게 만들지만, 더 많은 메모리를 소비하고 d.close() 연산을 더
    # 느리게 만듭니다.

    d.close()                  # 닫습니다

더 보기

모듈 `dbm`

  `dbm` 스타일 데이터베이스에 대한 범용 인터페이스.

모듈 `pickle`

  `shelve`에 의해 사용되는 객체 직렬화.