Python 딕셔너리 뷰는 실시간이며 (코드가 깨질 수 있음)
Source: Dev.to
Quick Quiz
d = {"a": 1, "b": 2}
keys = d.keys()
print(keys)
d["c"] = 3
print(keys)
만약 다음과 같이 기대했다면:
dict_keys(['a', 'b'])
dict_keys(['a', 'b'])
틀렸습니다. 실제 출력은:
dict_keys(['a', 'b'])
dict_keys(['a', 'b', 'c']) # ← 자동으로 업데이트됨!
Dictionary Views
.keys(), .values(), 그리고 .items()는 복사본을 반환하지 않습니다.
이들은 view 객체—딕셔너리를 실시간으로 비추는 창—이며, 딕셔너리가 변하면 자동으로 업데이트됩니다.
person = {"name": "Alice", "age": 30}
k = person.keys()
print(k) # dict_keys(['name', 'age'])
person["city"] = "NYC" # 키 추가
print(k) # dict_keys(['name', 'age', 'city'])
- 뷰는 데이터를 복사하지 않기 때문에 메모리 효율적입니다.
- 하지만 동기화된 상태를 기대하지 않으면 버그를 일으킬 수 있습니다.
Modifying While Iterating
실시간 뷰를 순회하면서 딕셔너리를 변형하면 오류가 발생합니다:
config = {"debug": True, "verbose": False, "temp_flag": True}
# True인 모든 플래그 제거
for key in config.keys():
if config[key] is True:
del config[key] # 💥 RuntimeError!
오류
RuntimeError: dictionary changed size during iteration
뷰가 순회 도중에 변하고, 파이썬은 예외를 발생시켜 이를 방지합니다.
Safe Way: Iterate Over a Snapshot
변형하기 전에 뷰를 리스트(또는 다른 정적 컨테이너)로 변환합니다:
config = {"debug": True, "verbose": False, "temp_flag": True}
# 리스트로 변환 – 스냅샷 생성
for key in list(config.keys()):
if config[key] is True:
del config[key]
print(config) # {'verbose': False}
list(config.keys())는 그 순간의 키들을 캡처하므로 원래 딕셔너리를 안전하게 수정할 수 있습니다.
Powerful Uses of Live Views
실시간 뷰는 딕셔너리 변화를 실시간으로 감시해야 할 때 유용합니다:
cache = {}
cache_keys = cache.keys()
# ... 코드의 다른 부분에서 ...
cache["user_123"] = data
cache["user_456"] = more_data
# cache_keys는 모든 추가를 자동으로 반영
print(f"Cached: {len(cache_keys)} items") # 항상 최신 상태
매번 .keys()를 다시 호출할 필요가 없으며, 뷰가 딕셔너리와 동기화된 상태를 유지합니다.
Conclusion
딕셔너리 뷰 객체는 실시간이며 메모리 효율적이고 강력하지만, 정적이라고 가정하면 미묘한 버그의 원인이 될 수 있습니다. 뷰와 스냅샷(list(dict.keys()))을 언제 사용해야 할지 알면 더 안전하고 예측 가능한 코드를 작성할 수 있습니다.
다음 책 Zero to AI Engineer: Python Foundations에서 발췌한 내용입니다.
원본은 Substack에 처음 공유되었습니다 →