Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 814 – frozendict 내장 타입 추가

Author:
Victor Stinner <vstinner at python.org>, Donghee Na <donghee.na at python.org>
Discussions-To:
Discourse thread
Status:
Final
Type:
Standards Track
Created:
12-Nov-2025
Python-Version:
3.15
Post-History:
13-Nov-2025
Resolution:
11-Feb-2026

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain or CC0-1.0, whichever is more permissive 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

Important

This PEP is a historical document. The up-to-date, canonical documentation can now be found at frozendict.

×

See PEP 1 for how to propose changes.

초록

새로운 공개 불변 타입 frozendictbuiltins모듈에 추가됩니다.

frozendict는 의도하지 않은 수정을 방지하므로 설계상 안전할 것으로 예상합니다. 이 추가는 CPython의 표준 라이브러리뿐만 아니라, 신뢰할 수 있는 불변 딕셔너리 타입을 활용할 수 있는 서드 파티 유지 관리자에게도 도움이 됩니다.

근거

제안된 frozendict타입은 다음을 수행합니다:

  • collections.abc.Mapping프로토콜을 구현합니다.
  • 피클링을 지원합니다.

다음 사용 사례는 불변 매핑이 바람직한 이유를 보여 줍니다:

  • 불변 매핑은 해시 가능하므로 딕셔너리 키 또는 집합 요소로 사용할 수 있습니다.
  • 이러한 해시 가능 속성으로 인해 @functools.lru_cache()로 데코레이트된 함수는 불변 매핑을 인자로 받을 수 있습니다. 불변 매핑과 달리, 이러한 함수에 일반 dict를 전달하면 오류가 발생합니다.
  • 불변 매핑을 함수 매개변수의 기본값으로 사용하면 변경 가능한 기본값의 문제를 피할 수 있습니다.

PyPI에는 이미 서드 파티 frozendictfrozenmap 패키지가 제공되고 있으며, 이는 불변 매핑에 대한 수요가 있음을 입증합니다.

사양

새로운 공개 불변 타입 frozendictbuiltins모듈에 추가됩니다. 이는 dict의 서브클래스가 아니라 object를 직접 상속합니다.

생성

frozendictdict와 유사한 생성 API를 구현합니다:

  • frozendict()는 비어 있는 새로운 불변 매핑을 생성합니다.
  • frozendict(**kwargs)**kwargs로부터 매핑을 생성합니다. 예: frozendict(x=1, y=2).
  • frozendict(collection)은 전달된 컬렉션 객체로부터 매핑을 생성합니다. 전달된 컬렉션 객체는 다음 중 하나일 수 있습니다:
    • dict입니다.
    • 다른 frozendict입니다.
    • 또는 키/값 튜플의 이터러블입니다.
  • frozendict(collection, **kwargs)는 앞의 두 생성을 결합합니다.

키는 해시 가능해야 하지만 값은 해시 불가능해도 됩니다. 해시 가능한 값을 사용하면 해시 가능한 frozendict가 생성됩니다.

dict에서 frozendict, 즉 frozendict(dict)를 생성하는 복잡도는 O(n)입니다. 항목은 얕은 복사됩니다.

삽입 순서가 보존됩니다.

반복

frozendict가 표준 collections.abc.Mapping 프로토콜을 구현하므로 반복에 필요한 모든 메서드를 지원합니다.:

assert list(m.items()) == [('foo', 'bar')]
assert list(m.keys()) == ['foo']
assert list(m.values()) == ['bar']
assert list(m) == ['foo']

frozendict를 반복할 때는 dict와 마찬가지로 삽입 순서를 사용합니다.

해싱 및 비교

frozendict 인스턴스는 튜플 객체와 마찬가지로 해시 가능하게 만들 수 있습니다.:

hash(frozendict(foo='bar'))  # works
hash(frozendict(foo=['a', 'b', 'c']))  # error, list is not hashable

해시 값은 항목의 순서에 의존하지 않습니다. 해시 값은 키와 값으로 계산됩니다. hash(frozendict)의 의사 코드:

hash(frozenset(frozendict.items()))

동등성 검사는 항목의 순서에 의존하지도 않습니다. 예제:

>>> a = frozendict(x=1, y=2)
>>> b = frozendict(y=2, x=1)
>>> hash(a) == hash(b)
True
>>> a == b
True

frozendictdict를 비교할 수 있습니다. 예제:

>>> frozendict(x=1, y=2) == dict(x=1, y=2)
True

합집합 연산자

병합(|) 연산자를 사용하여 두 frozendict를 결합하거나 frozendictdict를 결합할 수 있습니다. 예제:

>>> frozendict(x=1) | frozendict(y=1)
frozendict({'x': 1, 'y': 1})
>>> frozendict(x=1) | dict(y=1)
frozendict({'x': 1, 'y': 1})

일부 키가 공통으로 존재하면 오른쪽 피연산자의 값이 사용됩니다.:

>>> frozendict(x=1, y=2) | frozendict(y=5)
frozendict({'x': 1, 'y': 5})

업데이트 연산자 |=frozendict를 제자리에서 수정하지 않고 새로운 frozendict를 생성합니다.:

>>> d = frozendict(x=1)
>>> copy = d
>>> d |= frozendict(y=2)
>>> d
frozendict({'x': 1, 'y': 2})
>>> copy   # left unchanged
frozendict({'x': 1})

또한 PEP 584 “dict에 합집합 연산자 추가”를 참조하십시오.

복사

frozendict.copy()는 얕은 복사본을 반환합니다. CPython에서는 단순히 동일한 frozendict를 반환합니다(새 참조).

깊은 복사본을 얻으려면 copy.deepcopy()를 사용하십시오.

예제:

>>> import copy
>>> d = frozendict(mutable=[])
>>> shallow_copy = d.copy()
>>> deep_copy = copy.deepcopy(d)
>>> d['mutable'].append('modified')
>>> d
frozendict({'mutable': ['modified']})
>>> shallow_copy  # modified!
frozendict({'mutable': ['modified']})
>>> deep_copy     # unchanged
frozendict({'mutable': []})

타이핑

frozendict에 표준 typing 표기법을 사용할 수 있습니다.:

m: frozendict[str, int] = frozendict(x=1)

표현

frozendict는 표현에 특수 구문을 사용하지 않습니다. frozendict 인스턴스의 repr()는 다음과 같이 표시됩니다.

>>> frozendict(x=1, y=2)
frozendict({'x': 1, 'y': 2})

C API

다음 API를 추가하십시오.

  • PyAnyDict_Check(op) 매크로
  • PyAnyDict_CheckExact(op) 매크로
  • PyFrozenDict_Check() 매크로
  • PyFrozenDict_CheckExact() 매크로
  • PyFrozenDict_New(collection) 함수
  • PyFrozenDict_Type

frozendictdict 서브클래스가 아니더라도 PyDict_GetItemRef() 및 이와 유사한 “PyDict_Get” 함수와 함께 사용할 수 있습니다.

frozendictPyDict_SetItem() 또는 PyDict_DelItem()에 전달하면 TypeError가 발생합니다. frozendictPyDict_Check()를 적용한 결과는 거짓입니다.

dictfrozendict의 차이

  • dict에는 frozendict보다 더 많은 메서드가 있습니다.
    • __delitem__(key)
    • __setitem__(key, value)
    • clear()
    • pop(key)
    • popitem()
    • setdefault(key, value)
    • update(*args, **kwargs)
  • 모든 키와 값을 해시할 수 있다면 frozendicthash(frozendict)로 해시할 수 있습니다.

표준 라이브러리에서 frozendict의 가능한 후보

frozendict를 도입하면 안전성을 높이고 의도하지 않은 수정을 설계상 방지할 수 있는 여러 표준 라이브러리 모듈을 식별했습니다. 또한 아래에 나열된 것 외에도 추가적인 잠재적 사용 사례가 있다고 생각합니다. 그러나 이는 해당 모듈 유지 관리자의 승인 없이 이러한 변경을 진행할 의도가 있다는 뜻은 아닙니다.

참고: 변수를 수정된 새 frozendict 또는 새로운 변경 가능한 dict에 다시 바인딩하는 것은 여전히 가능합니다.

Python 모듈

함수 결과에서 dictfrozendict로 교체합니다.

  • email.headerregistry: ParameterizedMIMEHeader.params() (MappingProxyType을 교체)
  • enum: EnumType.__members__() (MappingProxyType을 교체)

상수에 대해 dictfrozendict로 교체합니다.

  • _opcode_metadata: _specializations, _specialized_opmap, opmap
  • _pydatetime: specs (_format_time()에서)
  • _pydecimal: _condition_map
  • bdb: _MonitoringTracer.EVENT_CALLBACK_MAP
  • dataclasses: _hash_action
  • dis: deoptmap, COMPILER_FLAG_NAMES
  • functools: _convert
  • gettext: _binary_ops, _c2py_ops
  • imaplib: Commands, Mon2num
  • json.decoder: _CONSTANTS, BACKSLASH
  • json.encoder: ESCAPE_DCT
  • json.tool: _group_to_theme_color
  • locale: locale_encoding_alias, locale_alias, windows_locale
  • opcode: _cache_format, _inline_cache_entries
  • optparse: _builtin_cvt
  • platform: _ver_stages, _default_architecture
  • plistlib: _BINARY_FORMAT
  • ssl: _PROTOCOL_NAMES
  • stringprep: b3_exceptions
  • symtable: _scopes_value_to_name
  • tarfile: PAX_NUMBER_FIELDS, _NAMED_FILTERS
  • token: tok_name, EXACT_TOKEN_TYPES
  • tomllib._parser: BASIC_STR_ESCAPE_REPLACEMENTS
  • typing: _PROTO_ALLOWLIST

frozendict 타입을 허용합니다.

  • builtins: eval()exec() (globals인자)

확장 모듈

상수에 대해 dictfrozendict로 교체합니다.

  • errno: errorcode

PEP 416 frozendict와의 관계

2012년 이후(PEP 416), Python 생태계가 발전했습니다.

  • asyncio는 2014년(Python 3.4)에 추가되었습니다.
  • 자유 스레딩은 2024년(Python 3.13)에 추가되었습니다.
  • concurrent.interpreters는 2025년(Python 3.14)에 추가되었습니다.

이제 변경 불가능한 매핑을 공유할 사용 사례가 더 많습니다.

frozendict은 이제 삽입 순서를 보존하지만, PEP 416의 frozendict는 순서가 없었습니다(PEP 603frozenmap처럼). frozendict은 Python 3.6부터 삽입 순서를 보존하는 dict 구현에 의존합니다.

frozendict를 추가한 첫 번째 동기는 Python에서 샌드박스를 구현하는 것이었습니다. 이 PEP에서는 더 이상 그렇지 않습니다.

types.MappingProxyType은 2012년(Python 3.3)에 추가되었습니다. 이 타입은 해시할 수 없으며, 이를 상속하는 것도 불가능합니다. 변경할 수 있는 원본 딕셔너리를 가져오기도 쉽습니다. 예를 들어 gc.get_referents()를 사용할 수 있습니다.

PEP 603 frozenmap과의 관계

collections.frozenmap은 frozendict와 다른 특성을 가집니다.

  • frozenmap 항목은 순서가 정해져 있지 않은 반면, frozendict은 삽입 순서를 보존합니다.
  • frozenmap에는 다음과 같은 추가 메서드가 있습니다.
    • including(key, value)
    • excluding(key)
    • union(mapping=None, **kw)

    frozenmap을 변경하는 이러한 메서드의 복잡도는 O(1)입니다.

  • 매핑 조회(mapping[key])의 복잡도는 frozenmap에서는 O(log n)이고, frozendict에서는 O(1)입니다.

참조 구현

  • https://github.com/python/cpython/pull/141508
  • frozendictdict 타입과 코드 대부분을 공유합니다.
  • PyDictObject를 상속하고 추가 ma_hash 멤버를 가지는 PyFrozenDictObject 구조체를 추가합니다.

스레드 안전성

frozendict가 생성되면 얕은 불변성이 보장됩니다. 이는 다른 스레드가 해당 값을 수정하지 않는 한 동기화 없이 스레드 간에 안전하게 공유할 수 있다는 의미입니다.

거부된 아이디어

dict에서 상속합니다

frozendictdict를 상속하면, 불변 frozendict를 변경하기 위해 dict 메서드를 호출할 수 있게 됩니다. 예를 들어 dict.__setitem__(frozendict, key, value)를 호출할 수 있게 됩니다.

dict 메서드를 사용하여 frozendict를 수정하지 못하게 할 수도 있지만, 그러려면 frozendict를 명시적으로 제외해야 하며, 이는 dict 성능에 영향을 줄 수 있습니다. 또한 일부 메서드에서 frozendict를 제외하는 것을 잊을 위험도 더 큽니다.

frozendictdict를 상속하지 않으면 이러한 문제가 없습니다.

보류된 아이디어

frozendict 리터럴의 새 구문

frozendict 리터럴을 작성하기 위한 다양한 구문이 제안되었습니다.

필요하다면 나중에 새 구문을 추가할 수 있습니다.

dictfrozendict로 변환하는 메서드

변경 가능한 dict를 변경 불가능한 frozendictO(1) 복잡도로 변환하는 여러 방법이 제안되었으며, 예를 들어 dict.freeze() 등이 있습니다. 한 가지 아이디어는 dict의 내용을 frozendict로 옮기는 것입니다. 그러면 dict가 비게 됩니다. 또 다른 아이디어는 “copy-on-write”를 사용하는 것입니다. dict를 처음 수정할 때만 복사합니다.

이러한 메서드는 필요할 경우 나중에 추가할 수 있지만, 지금 당장 추가해야 하는 것은 아니라고 봅니다. 또한 이러한 메서드를 추가한다면, list/tupleset/frozenset에 대해서도 비슷한 메서드를 추가하면 좋을 것입니다. 또한 PEP 351 (동결 프로토콜)을 참조하십시오.

타입 어노테이션

class TD(TypedDict, frozen=True) 또는 Frozen[MyTypedDict]를 추가하여 frozendict 타입을 정의하자는 내용이 제안되었습니다.

이러한 타입은 필요할 경우 나중에 추가할 수 있다고 봅니다.

참조

감사의 말

이 PEP는 Yury Selivanov(PEP 603)의 선행 작업을 기반으로 합니다.