파이썬에서 사전 복사 및 사본만 편집하는 방법
파이썬에서 사전을 복사하고 원본을 변경하지 않고 복사본만 편집하는 방법은 여러 가지가 있습니다. 각 방법에는 장단점이 있으며, 상황에 따라 적합한 방법을 선택하는 것이 중요합니다.
copy.deepcopy() 사용:
import copy
원본_사전 = {"a": 1, "b": 2, "c": 3}
복사_사전 = copy.deepcopy(원본_사전)
복사_사전["a"] = 10
print(원본_사전) # {'a': 1, 'b': 2, 'c': 3}
print(복사_사전) # {'a': 10, 'b': 2, 'c': 3}
copy.deepcopy()
는 재귀 함수를 사용하여 사전의 모든 계층을 복사합니다. 이는 원본 사전과 복사 사전이 서로 다른 메모리 위치에 저장되고 서로 독립적으로 변경될 수 있음을 의미합니다. 하지만 copy.deepcopy()
는 복사할 사전이 매우 크거나 복잡한 경우 성능 저하를 초래할 수 있다는 단점이 있습니다.
dict() 사용:
원본_사전 = {"a": 1, "b": 2, "c": 3}
복사_사전 = dict(원본_사전)
복사_사전["a"] = 10
print(원본_사전) # {'a': 1, 'b': 2, 'c': 3}
print(복사_사전) # {'a': 10, 'b': 2, 'c': 3}
dict()
함수는 사전을 직접 복사하는 간단한 방법입니다. copy.deepcopy()
와 마찬가지로 원본 사전과 복사 사전이 서로 다른 메모리 위치에 저장되고 서로 독립적으로 변경될 수 있습니다. 하지만 dict()
는 중첩된 사전을 복사하지 못한다는 단점이 있습니다.
사전 슬라이싱 사용:
원본_사전 = {"a": 1, "b": 2, "c": 3}
복사_사전 = 원본_사전.copy()
복사_사전["a"] = 10
print(원본_사전) # {'a': 1, 'b': 2, 'c': 3}
print(복사_사전) # {'a': 10, 'b': 2, 'c': 3}
사전 슬라이싱을 사용하면 사전의 일부를 복사할 수 있습니다. 이는 원본 사전의 특정 키-값 쌍만 복사해야 하는 경우에 유용합니다. 하지만 사전 슬라이싱은 사전의 전체 구조를 복사하지 못한다는 단점이 있습니다.
collections.abc.MutableMapping 상속:
from collections.abc import MutableMapping
class MyDict(MutableMapping):
def __init__(self, dict_):
self.data = dict_.copy()
def __getitem__(self, key):
return self.data[key]
def __setitem__(self, key, value):
self.data[key] = value
def __delitem__(self, key):
del self.data[key]
def __iter__(self):
return iter(self.data)
def __len__(self):
return len(self.data)
원본_사전 = {"a": 1, "b": 2, "c": 3}
복사_사전 = MyDict(원본_사전)
복사_사전["a"] = 10
print(원본_사전) # {'a': 1, 'b': 2, 'c': 3}
print(복사_사전) # {'a': 10, 'b': 2, 'c': 3}
예제 코드
import copy
원본_사전 = {"a": 1, "b": {"x": 10, "y": 20}, "c": 3}
복사_사전 = copy.deepcopy(원본_사전)
복사_사전["b"]["x"] = 30
print(원본_사전) # {'a': 1, 'b': {'x': 10, 'y': 20}, 'c': 3}
print(복사_사전) # {'a': 1, 'b': {'x': 30, 'y': 20}, 'c': 3}
원본_사전 = {"a": 1, "b": {"x": 10, "y": 20}, "c": 3}
복사_사전 = dict(원본_사전)
복사_사전["b"]["x"] = 30
print(원본_사전) # {'a': 1, 'b': {'x': 10, 'y': 20}, 'c': 3}
print(복사_사전) # {'a': 1, 'b': {'x': 30, 'y': 20}, 'c': 3}
원본_사전 = {"a": 1, "b": {"x": 10, "y": 20}, "c": 3}
복사_사전 = 원본_사전["b"].copy()
복사_사전["x"] = 30
print(원본_사전) # {'a': 1, 'b': {'x': 10, 'y': 20}, 'c': 3}
print(복사_사전) # {'x': 30, 'y': 20}
from collections.abc import MutableMapping
class MyDict(MutableMapping):
def __init__(self, dict_):
self.data = dict_.copy()
def __getitem__(self, key):
return self.data[key]
def __setitem__(self, key, value):
self.data[key] = value
def __delitem__(self, key):
del self.data[key]
def __iter__(self):
return iter(self.data)
def __len__(self):
return len(self.data)
원본_사전 = {"a": 1, "b": {"x": 10, "y": 20}, "c": 3}
복사_사전 = MyDict(원본_사전)
복사_사전["b"]["x"] = 30
print(원본_사전) # {'a': 1, 'b': {'x': 10, 'y': 20}, 'c': 3}
print(복사_사전) # {'a': 1, 'b': {'x': 30, 'y': 20}, 'c': 3}
참고:
- 위 코드는 Python 3.x 버전 기준입니다.
copy.deepcopy()
는 가장 안전하고 일반적인 방법이지만, 성능 저하를 초래할 수 있습니다.dict()
는 간단하고 빠르지만, 중첩된 사전을 복사하지 못합니다.- 사전 슬라이싱은 특정 키-값 쌍만 복사해야 하는 경우에 유용하지만, 사전의 전체 구조를 복사하지 못합니다.
collections.abc.MutableMapping
상속은 사용자 정의 사전 클래스를 만들 수 있는 강력한 방법이지만, 더 복잡하고 코드 길이가 늘어납니다.
선택 가이드:
- 원본 사전과 복사 사전을 완전히 독립적으로 유지해야 하고 성능이 중요하지 않은 경우:
copy.deepcopy()
- 간단하고 빠르게 사전을 복사해야 하고 중첩된 사전이 없는 경우:
dict()
- 원본 사전의 특정 키-값 쌍만 복사
대체 방법
위에서 소개된 방법 외에도 사전을 복사하고 사본만 편집하는 방법은 다음과 같습니다.
struct.pack() 및 struct.unpack() 사용:
import struct
원본_사전 = {"a": 1, "b": 2, "c": 3}
복사_사전 = struct.pack('iii', *원본_사전.values())
복사_사전 = struct.unpack('iii', 복사_사전)
복사_사전[0] = 10
print(원본_사전) # {'a': 1, 'b': 2, 'c': 3}
print(복사_사전) # (10, 2, 3)
이 방법은 사전을 바이너리 데이터로 변환하고 다시 언패킹하여 복사하는 방식입니다. 하지만 이 방법은 복잡하고 이해하기 어려울 수 있으며, 모든 사전 유형에 적용되지 않을 수 있습니다.
json.dumps() 및 json.loads() 사용:
import json
원본_사전 = {"a": 1, "b": 2, "c": 3}
복사_사전 = json.dumps(원본_사전)
복사_사전 = json.loads(복사_사전)
복사_사전["a"] = 10
print(원본_사전) # {'a': 1, 'b': 2, 'c': 3}
print(복사_사전) # {'a': 10, 'b': 2, 'c': 3}
이 방법은 사전을 JSON 문자열로 변환하고 다시 파싱하여 복사하는 방식입니다. 하지만 이 방법은 JSON 서식에 맞는 사전만 복사할 수 있으며, 성능이 느릴 수 있습니다.
pickle 사용:
import pickle
원본_사전 = {"a": 1, "b": 2, "c": 3}
with open('data.pickle', 'wb') as f:
pickle.dump(원본_사전, f)
with open('data.pickle', 'rb') as f:
복사_사전 = pickle.load(f)
복사_사전["a"] = 10
print(원본_사전) # {'a': 1, 'b': 2, 'c': 3}
print(복사_사전) # {'a': 10, 'b': 2, 'c': 3}
이 방법은 사전을 파일에 저장하고 다시 불러오는 방식으로 복사합니다. 하지만 이 방법은 파일 I/O를 사용하기 때문에 다른 방법들보다 느릴 수 있으며, 보안 문제가 발생할 수 있습니다.
주의 사항:
- 위 방법들은 모두 특정 상황에 따라 유용할 수 있지만, 각 방법마다 장단점이 있음을 기억해야 합니다.
- 사전을 복사하고 편집하는 방법을 선택할 때는 성능, 보안, 사용 편의성 등을 고려해야 합니다.
python dictionary reference