파이썬에서 dict의 딥 카피


341

dict파이썬 으로 깊은 사본을 만들고 싶습니다 . 불행히도이 .deepcopy()방법은에 존재하지 않습니다 dict. 어떻게합니까?

>>> my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
>>> my_copy = my_dict.deepcopy()
Traceback (most recent calll last):
  File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'deepcopy'
>>> my_copy = my_dict.copy()
>>> my_dict['a'][2] = 7
>>> my_copy['a'][2]
7

마지막 줄은이어야합니다 3.

수정 사항 my_dict이 스냅 샷에 영향을 미치지 않기를 바랍니다 my_copy.

어떻게합니까? 솔루션은 Python 3.x와 호환 가능해야합니다.


3
그것이 중복인지는 모르겠지만 stackoverflow.com/questions/838642/python-dictionary-deepcopy 는 엄청나게 가깝습니다.
charleslparker 2014 년

답변:


473

어때요?

import copy
d = { ... }
d2 = copy.deepcopy(d)

파이썬 2 또는 3 :

Python 3.2 (r32:88445, Feb 20 2011, 21:30:00) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import copy
>>> my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
>>> my_copy = copy.deepcopy(my_dict)
>>> my_dict['a'][2] = 7
>>> my_copy['a'][2]
3
>>>

16
실제로 그것은 내가 준 지나치게 단순화 된 예에서 작동합니다. 내 열쇠는 숫자가 아니라 물건입니다. 복사 모듈 설명서를 읽으면 키에 대한 __copy __ () / __ deepcopy __ () 메서드를 선언해야합니다. 저를 이끌어 주셔서 감사합니다!
Olivier Grégoire

3
파이썬 3.2와 2.7 코드에 차이가 있습니까? 그들은 나에게 동일하게 보인다. 그렇다면 단일 코드 블록과 "파이썬 3과 2 모두에 적합"이라는 문장이 더 좋을 것입니다.
MestreLion

30
copy.deepcopy스레드 안전하지 않다는 것도 언급 할 가치가 있습니다. 어려운 방법으로 배웠습니다. 반면에, 사용 사례에 따라 json.loads(json.dumps(d)) 입니다 스레드 안전하고, 잘 작동합니다.
rob

1
@ rob 당신은 그 의견을 답변으로 게시해야합니다. 실행 가능한 대안입니다. 나사산 안전 뉘앙스는 중요한 차이점입니다.
BuvinJ

3
@BuvinJ 문제는 json.loads파이썬 dict속성이 JSON 직렬화 가능하지 않은 모든 사용 사례의 문제를 해결하지 못한다 는 것입니다 . API와 같은 간단한 데이터 구조 만 다루는 사람들에게는 도움이 될 수 있지만 OP의 질문에 완전히 대답하는 솔루션으로는 충분하지 않다고 생각합니다.
rob

36

dict.copy ()는 사전에 대한 얕은 복사 기능이다
ID 당신에게 변수의 주소를 제공 내장되어 기능

먼저 "이러한 특정 문제가 발생하는 이유는 무엇입니까?"를 이해해야합니다.

In [1]: my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}

In [2]: my_copy = my_dict.copy()

In [3]: id(my_dict)
Out[3]: 140190444167808

In [4]: id(my_copy)
Out[4]: 140190444170328

In [5]: id(my_copy['a'])
Out[5]: 140190444024104

In [6]: id(my_dict['a'])
Out[6]: 140190444024104

키 'a'에 대한 두 가지 사전에있는 목록의 주소는 동일한 위치를 가리 킵니다.
따라서 my_dict에서 목록의 값을 변경하면 my_copy의 목록도 변경됩니다.


질문에 언급 된 데이터 구조에 대한 솔루션 :

In [7]: my_copy = {key: value[:] for key, value in my_dict.items()}

In [8]: id(my_copy['a'])
Out[8]: 140190444024176

또는 위에서 언급 한대로 심도 복사를 사용할 수 있습니다.


4
중첩 된 사전에는 솔루션이 작동하지 않습니다. 그런 이유로 딥 카피가 바람직하다.
Charles Plager

2
@CharlesPlager 합의! 그러나 목록 슬라이싱은 dict에서 작동하지 않습니다 value[:]. 해결책은 보편적 인 해결책이 아니라 문제에서 언급 한 특정 데이터 구조에 대한 것이었다.
theBuzzyCoder

17

파이썬 3.x

사본 가져 오기 딥 카피에서

my_dict = {'one': 1, 'two': 2}
new_dict_deepcopy = deepcopy(my_dict)

딥 카피가 없으면 도메인 사전에서 호스트 이름 사전을 제거 할 수 없습니다.

심층 복사가 없으면 다음과 같은 오류가 발생합니다.

"RuntimeError: dictionary changed size during iteration"

... 다른 사전 내 사전에서 원하는 요소를 제거하려고 할 때.

import socket
import xml.etree.ElementTree as ET
from copy import deepcopy

도메인은 사전 객체입니다

def remove_hostname(domain, hostname):
    domain_copy = deepcopy(domain)
    for domains, hosts in domain_copy.items():
        for host, port in hosts.items():
           if host == hostname:
                del domain[domains][host]
    return domain

출력 예 : [orginal] domains = { 'localdomain': { 'localhost': { 'all': '4000'}}}

[new] 도메인 = { 'localdomain': {}}}

그래서 여기서 일어나는 것은 사전 자체를 반복하는 것이 아니라 사전 사본을 반복하는 것입니다. 이 방법을 사용하면 필요에 따라 요소를 제거 할 수 있습니다.


-3

나는 Lasse V. Karlsen을 좋아하고 많은 것을 배웠다. 얕은 사전 복사본과 깊은 복사본의 차이점을 잘 보여주는 다음 예제로 수정했습니다.

    import copy

    my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
    my_copy = copy.copy(my_dict)
    my_deepcopy = copy.deepcopy(my_dict)

이제 변경하면

    my_dict['a'][2] = 7

하고

    print("my_copy a[2]: ",my_copy['a'][2],",whereas my_deepcopy a[2]: ", my_deepcopy['a'][2])

당신은 얻을

    >> my_copy a[2]:  7 ,whereas my_deepcopy a[2]:  3

1
이 답변이 Lasse V. Karlsen의 답변 과 다른 이유는 무엇 입니까? 다른 대답이 말하지 않는 것은 무엇입니까?
Olivier Grégoire

안녕하세요 올리비에! 나는 Lasse V. Karlsen의 대답 의 장점을 취하려고하지 않습니다 . 그는 본질적으로 내가 가진 문제를 해결했으며 그에게 빚을지고 있습니다. 내 의견은 다르지 않고 보완 적입니다. "copy"와 "deepcopy"를 대조하는 간단한 이유입니다. 이것은 내 문제의 원인이었습니다. 왜냐하면 동등한 방식으로 사용할 때 잘못되었습니다. 건배.
라파엘 몬테 이로

-9

더 간단한 (내 견해로는) 해결책은 새 사전을 만들고 이전 사전의 내용으로 업데이트하는 것입니다.

my_dict={'a':1}

my_copy = {}

my_copy.update( my_dict )

my_dict['a']=2

my_dict['a']
Out[34]: 2

my_copy['a']
Out[35]: 1

이 접근 방식의 문제점은 '충분히 깊지 않다'는 것입니다. 즉, 재귀 적으로 깊지 않습니다. 간단한 사전에는 충분하지만 중첩 된 사전에는 적합하지 않습니다. 다음은 깊이가 충분하지 않은 예입니다.

my_dict1={'b':2}

my_dict2={'c':3}

my_dict3={ 'b': my_dict1, 'c':my_dict2 }

my_copy = {}

my_copy.update( my_dict3 )

my_dict1['b']='z'

my_copy
Out[42]: {'b': {'b': 'z'}, 'c': {'c': 3}}

Deepcopy ()를 사용하면 세미 얕은 동작을 제거 할 수 있지만 응용 프로그램에 적합한 방법을 결정해야한다고 생각합니다. 대부분의 경우 걱정하지 않아도 될 수 있지만 가능한 함정에 대해 알고 있어야합니다 ... 마지막 예 :

import copy

my_copy2 = copy.deepcopy( my_dict3 )

my_dict1['b']='99'

my_copy2
Out[46]: {'b': {'b': 'z'}, 'c': {'c': 3}}

12
이것은 dict의 얕은 사본을 만들어 질문자가 요구 한 것이 아닙니다. 포함 된 개체는 자체적으로 복사되지 않습니다. 얕은 복사의 쉬운 방법은 my_dict.copy()!
Blckknght
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.